Perché esistono i costruttori
Nella pagina precedente hai costruito classi e creato oggetti con new. Un costruttore è il codice che viene eseguito proprio durante quella chiamata a new. Il suo unico scopo è restituire un oggetto pronto all'uso: tutti i campi necessari impostati, nessuno stato inizializzato a metà.
Un costruttore assomiglia a un metodo, con due differenze: ha lo stesso nome della classe e nessun tipo di ritorno, nemmeno void.
new Point(3, 4) alloca l'oggetto e poi esegue il corpo del costruttore con x = 3 e y = 4. Quando new restituisce il controllo, p è completamente inizializzato.
La parola chiave this
Nel costruttore qui sopra, i parametri si chiamano x e y, come i campi. this.x significa "il campo x di questo oggetto", mentre x da solo si riferisce al parametro. Senza this, x = x assegnerebbe il parametro a se stesso e lascerebbe il campo invariato.
this è necessario solo quando un parametro nasconde un campo, ma molti lo usano ovunque per chiarezza. L'errore comune è dimenticarlo quando i nomi coincidono: il codice compila, gira e lascia in silenzio i campi ai loro valori predefiniti (null, 0, false).
Il costruttore di default
Se non scrivi mai un costruttore, Java ne fornisce silenziosamente uno di default: un costruttore public, senza argomenti, che non fa niente di speciale. Ecco perché new funzionava su classi che non avevano alcun costruttore.
Il problema: appena scrivi un qualsiasi costruttore, quello gratuito sparisce.
class Box {
int size;
Box(int size) { // ora NON esiste un costruttore senza argomenti
this.size = size;
}
}
new Box(); // errore di compilazione: il costruttore Box() non esiste
Se vuoi ancora che new Box() funzioni, dichiara tu il costruttore senza argomenti:
Overloading dei costruttori
Una classe può avere più costruttori, purché le liste di parametri siano diverse: è semplicemente l'overloading dei metodi applicato ai costruttori. Ognuno offre un modo diverso di costruire l'oggetto.
Java sceglie il costruttore corrispondente in base al numero e ai tipi degli argomenti che passi a new.
Concatenare con this()
Nota la ripetizione qui sopra: ogni costruttore assegna i campi per conto suo. Puoi evitarlo facendo in modo che un costruttore ne chiami un altro con this(...). La chiamata deve essere la prima istruzione del costruttore.
Ora l'inizializzazione vera e propria sta in un unico punto. I costruttori più piccoli si limitano a fornire valori predefiniti e passare il lavoro. Se provi a mettere un'istruzione prima di this(...), il compilatore la rifiuta.
I costruttori e super()
Ogni costruttore chiama implicitamente per primo il costruttore della sua superclasse. Se non scrivi nulla, Java inserisce un super() nascosto (il costruttore senza argomenti della superclasse) all'inizio del corpo. Lo userai direttamente quando inizierai a creare sottoclassi, che è il prossimo argomento.
class Animal {
String name;
Animal(String name) { this.name = name; }
}
class Dog extends Animal {
Dog(String name) {
super(name); // qui bisogna chiamare esplicitamente il costruttore del padre
}
}
Dato che Animal non ha un costruttore senza argomenti, Dog deve chiamare esplicitamente super(name): non c'è un super() gratuito su cui ripiegare. Come this(), anche una chiamata a super(...) deve essere la prima istruzione del costruttore.
Prossimo passo: l'ereditarietà
I costruttori inizializzano un singolo oggetto, ma super() ha già accennato a qualcosa di più grande: le classi possono basarsi su altre classi, riutilizzandone campi, metodi e costruttori. Questa relazione, in cui una classe ne estende un'altra, si chiama ereditarietà, ed è l'argomento della prossima pagina.
Domande frequenti
Cos'è un costruttore in Java?
Un costruttore è un metodo speciale che viene eseguito quando crei un oggetto con new. Ha lo stesso nome della classe e nessun tipo di ritorno (nemmeno void). Il suo compito è portare il nuovo oggetto in uno stato iniziale valido, di solito assegnando gli argomenti del costruttore ai campi dell'oggetto.
Qual è la differenza tra un costruttore e un metodo in Java?
Un costruttore ha esattamente lo stesso nome della classe, non dichiara un tipo di ritorno e può essere invocato solo con new quando si crea un oggetto. Un metodo normale ha un nome proprio, dichiara un tipo di ritorno (o void) e viene chiamato su un oggetto già esistente. I costruttori inizializzano; i metodi lavorano dopo.
Cosa succede se non scrivo un costruttore in Java?
Il compilatore ti fornisce gratis un costruttore di default senza argomenti, che non riceve parametri e non fa nulla oltre alla chiamata implicita a super(). Ma nel momento in cui scrivi un qualsiasi costruttore, quello gratuito sparisce: se aggiungi un costruttore con parametri e vuoi ancora che new Thing() funzioni, devi dichiarare esplicitamente il costruttore senza argomenti.