O que são Métodos?

Métodos são sinônimos de funções, mas o pessoal do Java quis ser diferentão e escolheu outro nome para a mesmíssima coisa. Se você já definiu uma função em Python, C, C++ ou outra linguagem, é praticamente a mesma coisa.

Como definir um método?

Uma definição simples de um método seria algo como:

nivel_acesso tipo_retorno nome_metodo(parametros....) {
    /* ... */
    return ; // se for void não tem retorno!
}

Por exemplo, podemos definir um método que realiza um cálculo muito complexo de forma muito inteligente da seguinte forma:

public double calculaChopSuey(double x, int y) {
    /* código muito perspicaz aqui */
    return resultado;
}

public: é um modificador de acesso, indica a visibilidade de um método.
double: o tipo de variável que é retornado pelo método;
entre parentesis: todos os parametros que a função recebe como input


Como escolher o modificador de acesso que preciso??

  • public tem a visibilidade pública; todo mundo consegue te acessar, não importa se está em outro package, classe e etc;
  • protected somente as subclasses ou o mesmo package conseguem acessar;
  • private somente a própria classe tem acesso, nem mesmo as classes filhas conseguem usar;
  • sem modificador ao omitir o modificador, será utilizado um modificador default: qualquer um no mesmo package acessam (subclasses podem acessar SE estiverem no mesmo package!)

Por exemplo:

// arquivo: Animal.java
public class Animal {
  void falar() {  // modificador default!
    System.out.println("estou confuso...");
  }
}

// arquivo: Gato.java
public class Gato extends Animal {
  public static void main(String[] args) {
    var agata = new Gato();
    agata.falar();  // usa o falar() definido em Animal!
  }
}

O Gato consegue “falar” se o método na classe Animal for: public, protected ou default
O Gato não consegue “falar” se o método na classe Animal for: private

Já se estiverem em packages diferentes…

// arquivo: animal/Animal.java
package animal;
public class Animal {
  protected void falar() {
    System.out.println("estou confuso...");
  }
}

// arquivo: gato/Gato.java
package gato;
import animal.Animal;
public class Gato extends Animal {
  public static void main(String[] args) {
    var gato = new Gato();
    gato.falar(); // printa: estou confuso...
  }
}

O Gato consegue “falar” se o método na classe Animal for: public ou protected
O Gato não consegue “falar” se o método na classe Animal for: private ou default


Sobrescrever um método

O que acontece se eu quiser que meu gato agora solte um miau?
Nesse caso basta você definir um novo método com outros nomes:

...
  protected void falarGato()
  ...
  protected void falarCachorro()
  ...
  protected void falarHumano()
  ...

Dessa forma o código cresce muito e você teria que olhar sempre como um determinado método está definido para utilizar corretamente, facilitando escrever algo errado, trabalhar 2x e introduzir bugs e etc;

Para evitar isso em Java (e outras linguages) você pode mudar o comportamento de um método herdado, basta sobrescrever ele redefinindo do zero:

package gato;
import animal.Animal;
public class Gato extends Animal {

  @Override // é opcional, mas recomendado!
  protected void falar() {
    System.out.println("miaauu");
  }

  public static void main(String[] args) {
    var gato = new Gato();
    gato.falar(); // printa: miaauu
  }
}

toString

Em Java há um método fundamental chamado toString() que irá mostrar em formato de string uma representação daquele objeto. Ele é invocado automaticamente ao “printar” um objeto, como a seguir:

/*packages, imports e definição da classe aqui */
public static void main(String[] args) {
  var gato = new Gato();
  System.out.println(gato); // printa: gato.Gato@6ff3c5b5
}

É possível sobrescrever este método para printar algo que você queira:

/*packages, imports e definição da classe aqui */
@Override
public String toString() {
  return "Olá, eu sou um gato!"
}
public static void main(String[] args) {
  var gato = new Gato();
  System.out.println(gato); // printa: Olá, eu sou um gato!
}

O método toString() é geralmente sobrescrito para printar algo mais informativo de um objeto de forma legível, como seus atributos, por exemplo.