Attributi di Classe Java (Campi)
Dichiara campi istanza in una classe Java, imposta i valori iniziali e accedi ad essi tramite gli oggetti.
Gli attributi di una classe sono le variabili dichiarate al suo interno — i dati che ogni oggetto porta con sé. La maggior parte degli autori li chiama campi (come fa la Java Language Specification), mentre "attributo" è il termine OOP più generico; significano la stessa cosa. Questo capitolo riguarda la loro dichiarazione, i valori iniziali e come leggerli e scriverli dall'esterno della classe.
Dichiarare un campo
Un campo assomiglia a una variabile locale, ma si trova nel corpo della classe anziché all'interno di un metodo:
public class Book {
String title;
String author;
int pages;
boolean inPrint;
}Ogni istanza di Book ottiene la propria copia di questi quattro campi. Due libri hanno due stringhe title separate, due int pages separati, e così via. Vivono per tutta la durata dell'oggetto, cioè finché nulla lo referenzia più.
Valori predefiniti
Se non inizializzi un campo, Java lo inizializza al posto tuo. I valori predefiniti dipendono dal tipo:
| Tipo | Predefinito |
|---|---|
byte, short, int, long | 0 |
float, double | 0.0 |
char | '�' (il carattere null, code point 0 — non uno spazio) |
boolean | false |
| qualsiasi tipo oggetto | null |
Book b = new Book();
System.out.println(b.title); // null
System.out.println(b.pages); // 0
System.out.println(b.inPrint); // falseQuesta è una delle principali differenze tra i campi e le variabili locali nei metodi — le variabili locali non hanno un valore predefinito e il compilatore rifiuta di leggerle prima di assegnarle. I campi iniziano sempre con qualcosa.
Inizializzatori inline
Puoi assegnare un valore a un campo direttamente dove lo dichiari:
public class Book {
String title = "Untitled";
int pages = 0;
boolean inPrint = true;
}L'inizializzatore viene eseguito una volta per oggetto, al momento della sua creazione. Viene eseguito in ordine di dichiarazione, prima del corpo del costruttore. Se un campo necessita di un'inizializzazione più complessa, quello è il compito del costruttore.
Leggere e scrivere i campi
Si usa <riferimento>.<campo> dall'esterno, e semplicemente <nomeCampo> (o this.<nomeCampo>) dall'interno della classe stessa:
Book b = new Book();
b.title = "Effective Java"; // write
String t = b.title; // readAll'interno della classe:
public class Book {
String title;
void rename(String t) {
title = t; // same as this.title = t;
}
}Il capitolo sulla parola chiave this spiega quando è necessario il qualificatore esplicito this. e quando non lo è.
Convenzioni di nomenclatura
I nomi dei campi Java usano il lowerCamelCase:
String firstName; // good
String first_name; // not Java style
String FirstName; // looks like a classI boolean vengono spesso nominati con i prefissi is o has (isPublished, hasIndex), rendendo i punti di chiamata leggibili in modo naturale: if (book.isPublished). Le costanti — campi che non cambiano — sono scritte in UPPER_SNAKE_CASE e contrassegnate con static final, trattate nei capitoli su static e final.
Campi istanza vs campi di classe
Per impostazione predefinita, i campi appartengono a ogni istanza — ogni oggetto ha la propria copia. Aggiungendo static, il campo appartiene alla classe stessa; esiste esattamente una copia, condivisa tra tutte le istanze:
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 classTroverai la spiegazione completa nel capitolo su static; per ora, supponi che ogni campo sia un campo istanza a meno che non sia esplicitamente contrassegnato con static.
I campi pubblici sono quasi sempre un errore
Java consente di scrivere public String title; e permettere al codice esterno di accedervi e modificarlo direttamente. In pratica quasi non lo si fa mai. Una volta che un campo è pubblico, si perde la capacità di validare le scritture, cambiare il tipo in seguito o aggiungere logica alle letture — chiunque tocchi il campo è vincolato alla sua rappresentazione attuale.
Il pattern standard è contrassegnare i campi come private ed esporre invece getter e setter:
public class Book {
private String title;
public String getTitle() { return title; }
public void setTitle(String t) { this.title = t; }
}Questo è l'incapsulamento. I capitoli su incapsulamento e getter e setter coprono il pattern completo. Negli esempi iniziali mostriamo i campi direttamente per chiarezza, ma il vero codice Java li mantiene privati.
I campi contengono riferimenti, non oggetti
Quando il tipo di un campo è una classe (non un tipo primitivo), il campo è un riferimento. Due oggetti possono condividere lo stesso oggetto sottostante attraverso i loro campi:
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. BlochValgono gli stessi avvertimenti del capitolo precedente: a volte è ciò che si vuole, a volte è un bug. Se un Book deve avere il proprio Author, bisogna assegnare new Author() a ciascuno.
Un esempio pratico
Cosa c'è dopo
I campi rappresentano lo stato di un oggetto. L'altra metà — il suo comportamento — risiede nei metodi dichiarati sulla classe. Il prossimo capitolo sui metodi di classe mostra come associare metodi alle istanze e come accedono ai campi appena definiti.