Métodos de Classe em Java
Adicione métodos de instância a uma classe Java para dar comportamento aos objetos e operar sobre seus campos.
Os métodos de uma classe são o que dão comportamento aos seus objetos. Os campos definem o que um objeto é; os métodos descrevem o que ele pode fazer. Até agora, os métodos que você escreveu eram static — utilitários que pertencem à própria classe. Este capítulo trata dos métodos de instância, que pertencem a cada objeto e operam sobre seus campos.
O termo "métodos de classe" em Java é um pouco ambíguo. A maioria dos autores usa-o para se referir a métodos definidos dentro de uma classe — o que inclui os dois tipos. Alguns o utilizam estritamente para designar métodos static (pois estes literalmente pertencem à classe). Abordaremos os métodos de instância aqui, e os métodos static têm um capítulo próprio em Java static.
Um método de instância
Adicione um método ao corpo da classe, sem static, e ele passará a fazer parte de cada instância:
public class Circle {
double radius;
double area() {
return Math.PI * radius * radius;
}
}Agora todo Circle que você criar pode responder a area():
Circle c = new Circle();
c.radius = 5;
System.out.println(c.area()); // 78.539...O corpo lê radius sem qualificação — Java resolve o nome simples como this.radius, o campo do objeto sobre o qual o método foi chamado.
this — o receptor
Todo método de instância tem um parâmetro invisível chamado this, que se refere ao objeto sobre o qual o método foi chamado:
Circle a = new Circle(); a.radius = 2;
Circle b = new Circle(); b.radius = 5;
a.area(); // inside area(), this == a, so this.radius == 2
b.area(); // inside area(), this == b, so this.radius == 5O mesmo método compilado é executado nos dois casos; o que muda é qual objeto this referencia. O capítulo da palavra-chave this explica quando você precisa escrever this. explicitamente e quando pode omiti-lo.
Métodos que alteram o estado
Um método também pode escrever em campos. Tais métodos são frequentemente chamados de mutadores:
public class Counter {
int count;
void increment() {
count++; // mutates this.count
}
void reset() {
count = 0;
}
int get() {
return count;
}
}
Counter c = new Counter();
c.increment(); c.increment(); c.increment();
System.out.println(c.get()); // 3A mutação por meio de métodos é como os objetos evoluem ao longo do tempo sem que código externo toque diretamente em seus campos. Os métodos que apenas leem um campo e o retornam são o espelho disso — geralmente chamados de acessores ou getters (int get() acima é um exemplo). Rotear leituras e escritas por meio de métodos, em vez de expor os campos diretamente, é a ideia central por trás do encapsulamento: o objeto permanece no controle dos seus próprios dados.
Chamando outros métodos a partir de dentro
Métodos de instância podem chamar outros métodos no mesmo objeto, simplesmente pelo nome:
public class Rectangle {
double width, height;
double area() { return width * height; }
double perimeter() { return 2 * (width + height); }
String describe() {
return "area=" + area() + ", perimeter=" + perimeter();
}
}O compilador transforma area() e perimeter() dentro de describe em this.area() e this.perimeter(). Eles chamam os métodos no retângulo sobre o qual describe foi invocado.
Static vs instância — qual usar
A regra prática: o método depende do estado por objeto?
- Se sim, é um método de instância (sem
static). - Se não, é
static.
public class Math2 {
public static int squared(int n) { // pure calculation — static
return n * n;
}
}
public class Counter {
int count;
public void increment() { // reads/writes this.count — instance
count++;
}
}Um sinal comum de problema é um método de instância que ignora this completamente — isso é um método static disfarçado. O capítulo Java static aborda os prós e contras.
Chamar um método de instância requer uma instância
Como os métodos de instância leem this, você não pode chamá-los sem um objeto:
Counter.increment(); // ERROR — increment is not static
new Counter().increment(); // fine — increment is called on a fresh Counter (which is then thrown away)
Counter c = new Counter();
c.increment(); // fine — increment is called on cEste é o erro de compilação mais comum para iniciantes: um método não estático referenciado a partir de um contexto estático (tipicamente dentro de main, que é estático).
Se o compilador indicar non-static method increment() cannot be referenced from a static context, você quase certamente chamou um método de instância sem um objeto — por exemplo Counter.increment() em vez de c.increment(). Crie uma instância primeiro e depois chame o método sobre ela.
Sobrecarga e sobrescrita
Os métodos de instância suportam ambas:
- Sobrecarga (overloading): múltiplos métodos com o mesmo nome mas listas de parâmetros diferentes na mesma classe (abordado em sobrecarga de método).
- Sobrescrita (overriding): uma subclasse substituindo a versão herdada de um método (abordado em sobrescrita de método).
Você já viu sobrecarga na Parte 5. Sobrescrita é um dos grandes benefícios da herança e aparece em breve.
Corpos de métodos são blocos
O corpo de um método é apenas um bloco de código comum — variáveis declaradas nele são locais à chamada, o fluxo de controle funciona igual a qualquer outro lugar, e você pode retornar cedo. Nada no fato de "estar em uma classe" muda como o corpo é lido. A única capacidade extra é que identificadores simples agora podem se referir aos campos e outros métodos do objeto.
Um exemplo completo
Este exemplo reúne acessores (area, perimeter), um mutador (scale) e um método que chama outros métodos (describe) em uma única classe. Rectangle é declarado como static class apenas para que toda a demonstração caiba em um único arquivo — essa palavra-chave se aplica à classe aninhada, não aos seus métodos de instância, que ainda são executados em um retângulo específico. Observe que escalar r não altera s: cada objeto carrega seu próprio estado.
O que vem a seguir
Até agora você criou objetos escrevendo new Dog() e preenchendo os campos linha a linha. Isso é verboso e sujeito a erros — e fácil de esquecer. A solução é um construtor, um método especial que é executado quando o objeto é criado. Continue para o capítulo de construtores.