Classes e Objetos em Java
Defina uma classe Java e crie objetos (instâncias) a partir dela — a base do modelo orientado a objetos do Java.
Uma classe é uma definição; um objeto é uma instância dessa definição existindo em tempo de execução. A classe descreve como um cachorro é e o que pode fazer; um objeto é Rex, um cachorro específico que vive na memória enquanto seu programa executa. Tudo abaixo se baseia nessa distinção.
Definindo uma classe
Uma definição de classe fica em seu próprio arquivo .java, com o nome da classe. O corpo contém campos (os dados que cada instância carrega) e métodos (o comportamento que cada instância pode executar).
public class Dog {
String name;
int age;
void describe() {
System.out.println(name + ", age " + age);
}
}Isso declara um tipo. Ainda não cria nenhum cachorro — exatamente como escrever int não cria um inteiro.
Criando um objeto com new
A palavra-chave new pede à JVM que aloque espaço para uma instância e retorne uma referência para ela:
Dog d = new Dog();Três coisas acontecem nessa linha:
- Alocação. A JVM encontra espaço no heap suficiente para um
Dog. - Inicialização padrão. Cada campo recebe um valor padrão —
nullpara objetos,0para ints,falsepara booleans. - Chamada do construtor. O
()invoca um construtor. Não escrevemos um, então o Java forneceu um construtor padrão sem argumentos que não faz nada a mais. O próximo capítulo sobre construtores cobre como escrever os seus próprios.
Após isso, d contém uma referência — um valor pequeno que aponta para o objeto no heap. O objeto em si é a coisa maior no heap.
Lendo e escrevendo campos
Você acessa um campo escrevendo <referência>.<campo>:
d.name = "Rex";
d.age = 3;
System.out.println(d.name); // RexO acesso a campos também é como você chama métodos:
d.describe(); // Rex, age 3O ponto é o mesmo nos dois casos; se o lado direito é um campo ou um método depende apenas do que vem a seguir.
Referências não são o objeto
Esta é a frase mais importante deste capítulo: uma variável de tipo de classe contém uma referência, não o próprio objeto.
Dog a = new Dog();
a.name = "Rex";
Dog b = a; // copies the REFERENCE, not the dog
b.name = "Buddy";
System.out.println(a.name); // Buddya e b apontam para o mesmo objeto no heap, então modificá-lo por um é visível pelo outro. Compare com primitivos:
int x = 5;
int y = x; // copies the value
y = 9;
System.out.println(x); // still 5x e y são independentes — primitivos são copiados por valor. O capítulo sobre passagem por valor aprofunda o que isso significa para argumentos de método.
null e NullPointerException
Uma variável de referência pode ser null, significando "não aponta para nenhum objeto":
Dog d = null;
d.describe(); // NullPointerExceptionnull é o que você obtém se nunca atribuiu um objeto, ou se um campo de tipo objeto nunca foi inicializado explicitamente. Desreferenciar null (escrever d.algo quando d == null) lança NullPointerException em tempo de execução. Escrever código que não explode em null é metade do Java prático.
NullPointerException é um erro em tempo de execução, não um erro de compilação — o código compila normalmente e só falha quando aquela linha de fato é executada. A correção é garantir que a variável aponte para um objeto real primeiro (d = new Dog();) ou proteger com uma verificação (if (d != null) d.describe();) antes de desreferenciá-la.Comparando objetos: == vs equals
Para referências, == pergunta "essas duas variáveis apontam para o mesmo objeto?":
Dog a = new Dog();
Dog b = new Dog();
Dog c = a;
System.out.println(a == b); // false — different objects
System.out.println(a == c); // true — same objectSe você quiser comparar o conteúdo de dois objetos, chame um método equals em vez disso — toda classe herda um padrão de Object, mas o padrão apenas faz igualdade de referência. Você sobrescreve equals para significar o que quiser; consulte o capítulo equals & hashCode mais adiante nesta parte.
Um arquivo, muitos objetos
Uma única definição de classe suporta instâncias ilimitadas. Todas compartilham o layout, mas cada uma tem seu próprio estado:
Dog rex = new Dog(); rex.name = "Rex"; rex.age = 3;
Dog molly = new Dog(); molly.name = "Molly"; molly.age = 7;
rex.describe(); // Rex, age 3
molly.describe(); // Molly, age 7Um método como describe lê de this — o objeto no qual foi chamado — portanto o mesmo código imprime saídas diferentes dependendo de qual instância você o chama.
Onde as classes ficam
Um arquivo .java que declara public class Dog deve se chamar Dog.java. Você pode ter classes não públicas no mesmo arquivo, mas apenas uma classe public por arquivo, e seu nome deve corresponder ao nome do arquivo. Para programas pequenos neste capítulo, frequentemente colocaremos classes auxiliares dentro do mesmo arquivo que main usando classes aninhadas static, apenas para manter o exemplo em um único arquivo.
Um exemplo completo
O que vem a seguir
Você pode declarar uma classe e instanciá-la, mas até agora o único campo que escreveu foi "qualquer valor serve." O próximo capítulo sobre atributos de classe percorre os campos adequadamente — declaração, padrões, escopo de instância versus classe, e as convenções que o código Java segue.