Atributos de Classe Java (Campos)
Declare campos de instância em uma classe Java, defina valores iniciais e acesse-os através de objetos.
Os atributos de uma classe são as variáveis declaradas dentro dela — os dados que cada objeto carrega. A maioria dos autores os chama de campos (como faz a Especificação da Linguagem Java), e "atributo" é o termo mais geral da POO; eles significam a mesma coisa. Este capítulo trata de como declará-los, quais valores eles recebem inicialmente e como lê-los e escrevê-los de fora da classe.
Declarando um campo
Um campo se parece com uma variável local, mas fica no corpo da classe em vez de dentro de um método:
public class Book {
String title;
String author;
int pages;
boolean inPrint;
}Cada instância de Book recebe sua própria cópia desses quatro campos. Dois livros têm duas strings title separadas, dois ints pages separados e assim por diante. Eles vivem enquanto o objeto existir, ou seja, até que nada mais o referencie.
Valores padrão
Se você não inicializar um campo, o Java o inicializa para você. Os valores padrão dependem do tipo:
| Tipo | Padrão |
|---|---|
byte, short, int, long | 0 |
float, double | 0.0 |
char | '�' (o caractere nulo, ponto de código 0 — não um espaço) |
boolean | false |
| qualquer tipo de objeto | null |
Book b = new Book();
System.out.println(b.title); // null
System.out.println(b.pages); // 0
System.out.println(b.inPrint); // falseEste é um dos principais pontos em que os campos diferem das variáveis locais dentro de métodos — variáveis locais não recebem valor padrão, e o compilador se recusa a deixar você ler uma antes de atribuir um valor a ela. Os campos sempre começam com algum valor.
Inicializadores inline
Você pode dar a um campo um valor logo onde o declara:
public class Book {
String title = "Untitled";
int pages = 0;
boolean inPrint = true;
}O inicializador é executado uma vez por objeto, quando esse objeto é criado. Ele é executado na ordem de declaração, antes do corpo do construtor. Se um campo precisa de uma configuração mais complexa, esse é o trabalho do construtor.
Lendo e escrevendo campos
Você usa <referência>.<campo> de fora, e apenas <nomeDoCampo> (ou this.<nomeDoCampo>) de dentro da própria classe:
Book b = new Book();
b.title = "Effective Java"; // write
String t = b.title; // readDentro da classe:
public class Book {
String title;
void rename(String t) {
title = t; // same as this.title = t;
}
}O capítulo sobre a palavra-chave this explica quando você precisa do qualificador explícito this. e quando não precisa.
Convenções de nomenclatura
Os nomes de campos Java usam lowerCamelCase:
String firstName; // good
String first_name; // not Java style
String FirstName; // looks like a classBooleanos costumam ter prefixos is ou has (isPublished, hasIndex), tornando os locais de chamada mais legíveis: if (book.isPublished). Constantes — campos que não mudam — são escritas em UPPER_SNAKE_CASE e marcadas com static final, abordadas nos capítulos sobre static e final.
Campos de instância vs. campos de classe
Por padrão, os campos pertencem a cada instância — cada objeto tem sua própria cópia. Adicione static e o campo passa a pertencer à classe em si; há exatamente uma cópia, compartilhada por todas as instâncias:
public class Counter {
int count; // instance — each Counter has its own
static int total; // class — one shared by all Counters
}
Counter a = new Counter();
Counter b = new Counter();
a.count++; b.count++; b.count++;
Counter.total++;
System.out.println(a.count); // 1
System.out.println(b.count); // 2
System.out.println(Counter.total); // 1, accessed through the classVocê verá a história completa no capítulo sobre static; por enquanto, assuma que todo campo é um campo de instância, a menos que seja explicitamente marcado com static.
Campos públicos geralmente são um erro
O Java permite que você escreva public String title; e deixe código externo acessar e modificar o campo diretamente. Na prática, você quase nunca faz isso. Uma vez que um campo é público, você perde a capacidade de validar escritas, mudar o tipo mais tarde ou envolver leituras com lógica — qualquer um que toque o campo fica acoplado à sua representação atual.
O padrão padrão é marcar os campos como private e expor getters e setters em vez disso:
public class Book {
private String title;
public String getTitle() { return title; }
public void setTitle(String t) { this.title = t; }
}Isso é encapsulamento. Os capítulos sobre encapsulamento e getters & setters cobrem o padrão completo. Estamos mostrando campos diretamente nos exemplos iniciais para maior clareza, mas o código Java real os mantém privados.
Campos armazenam referências, não objetos
Quando o tipo de um campo é uma classe (não um primitivo), o campo é uma referência. Dois objetos podem compartilhar o mesmo objeto subjacente por meio de seus campos:
public class Author { String name; }
public class Book { Author author; }
Author a = new Author();
a.name = "Joshua Bloch";
Book b1 = new Book(); b1.author = a;
Book b2 = new Book(); b2.author = a; // same Author object
a.name = "J. Bloch";
System.out.println(b1.author.name); // J. Bloch
System.out.println(b2.author.name); // J. BlochOs mesmos avisos do capítulo anterior se aplicam: isso às vezes é o que você quer e às vezes é um bug. Se um Book deve ter seu próprio Author, você atribuiria new Author() a cada um.
Um exemplo prático
O que vem a seguir
Os campos são o estado de um objeto. A outra metade — seu comportamento — vive nos métodos declarados na classe. O próximo capítulo sobre métodos de classe mostra como associar métodos a instâncias e como eles acessam os campos que você acabou de definir.