Costruttori in Java

Concetti Chiave
  • I costruttori sono metodi speciali utilizzati per inizializzare gli oggetti al momento della loro creazione.
  • Un costruttore ha lo stesso nome della classe e non ha un tipo di ritorno.
  • I costruttori possono accettare parametri per personalizzare l'inizializzazione degli oggetti.
  • Se non viene definito un costruttore, Java fornisce un costruttore di default che inizializza le variabili di istanza ai valori predefiniti (zero, null, false).

Costruttori

Riprendiamo l'esempio della classe Scatola che abbiamo visto in precedenza:

class Scatola {
    double larghezza;
    double altezza;
    double profondita;
}

In questo esempio, la classe Scatola ha tre variabili di istanza: larghezza, altezza e profondita. Queste variabili sono utilizzate per memorizzare le dimensioni della scatola. Tuttavia, non sono inizializzate, il che significa che quando si crea un oggetto Scatola, queste variabili non hanno valori definiti.

Vi sono vari metodi per inizializzare le variabili di istanza di un oggetto. Un modo semplice ma sconveniente è quello di inizializzare i campi manualmente:

Scatola miaScatola = new Scatola();

// assegna valori alle variabili d'istanza di miaScatola
miaScatola.larghezza = 10;
miaScatola.altezza  = 20;
miaScatola.profondita = 15;

Oppure, si può definire un metodo di convenienza per impostare le dimensioni della scatola:

class Scatola {
    double larghezza;
    double altezza;
    double profondita;

    // metodo di convenienza per impostare le dimensioni della scatola
    void impostaDim(double l, double a, double p) {
        larghezza = l;
        altezza = a;
        profondita = p;
    }
}

Può essere noioso inizializzare tutte le variabili in una classe ogni volta che viene creato un oggetto. Il problema è che stiamo separando la creazione dell'oggetto dalla sua inizializzazione.

Anche aggiungendo metodi di convenienza come impostaDim(), sarebbe più semplice e conciso avere tutta la configurazione fatta al momento in cui l'oggetto viene creato per la prima volta.

Poiché il requisito di inizializzazione è così comune, Java permette agli oggetti di inizializzarsi automaticamente quando vengono creati. Questa inizializzazione automatica è eseguita tramite l'uso di un costruttore.

Un costruttore inizializza un oggetto immediatamente alla creazione. Ha lo stesso nome della classe in cui risiede ed è sintatticamente simile a un metodo.

Una volta definito, il costruttore viene chiamato automaticamente quando l'oggetto viene creato, prima che l'operatore new completi l'operazione. I costruttori possono sembrare un po' strani perché non hanno un tipo di ritorno, nemmeno void. Questo perché il tipo di ritorno implicito del costruttore di una classe è il tipo della classe stessa.

È compito del costruttore inizializzare lo stato interno di un oggetto affinché il codice che crea un'istanza abbia a disposizione un oggetto completamente inizializzato e utilizzabile immediatamente.

Si può rielaborare l'esempio di Scatola in modo che le dimensioni della scatola siano inizializzate automaticamente quando l'oggetto è costruito. A tal fine, sostituire impostaDim() con un costruttore. Si comincia definendo un costruttore semplice che imposta le dimensioni di ogni scatola agli stessi valori. Questa versione è mostrata qui:

/* Qui, Scatola usa un costruttore per inizializzare
   le dimensioni di una scatola.
*/
class Scatola {
    double larghezza;
    double altezza;
    double profondita;

    // Questo è il costruttore per Scatola.
    Scatola() {
        System.out.println("Costruzione di Scatola");
        larghezza = 10;
        altezza = 10;
        profondita = 10;
    }

    // calcola e restituisce il volume
    double volume() {
        return larghezza * altezza * profondita;
    }
}

class DimostrazioneScatola6 {
    public static void main(String[] args) {
        // dichiarare, allocare e inizializzare oggetti Scatola
        Scatola miaScatola1 = new Scatola();
        Scatola miaScatola2 = new Scatola();

        double volume;

        // ottenere il volume della prima scatola
        volume = miaScatola1.volume();
        System.out.println("Il volume è " + volume);

        // ottenere il volume della seconda scatola
        volume = miaScatola2.volume();
        System.out.println("Il volume è " + volume);
    }
}

Quando questo programma viene eseguito, genera i seguenti risultati:

Costruzione di Scatola
Costruzione di Scatola
Il volume è 1000.0
Il volume è 1000.0

Come si può vedere, sia miaScatola1 che miaScatola2 sono state inizializzate dal costruttore Scatola() quando sono state create.

Poiché il costruttore assegna a tutte le scatole le stesse dimensioni, 10 per 10 per 10, sia miaScatola1 che miaScatola2 avranno lo stesso volume.

L'istruzione println() all'interno di Scatola() è solo a scopo illustrativo. La maggior parte dei costruttori non visualizzerà nulla. Si limiteranno a inizializzare un oggetto.

Prima di procedere, si riveda l'operatore new. Come è noto, quando si alloca un oggetto, si utilizza la seguente forma generale:

variabile_classe = new nomeClasse();

Ora si può capire perché le parentesi sono necessarie dopo il nome della classe. Quello che sta realmente accadendo è che viene chiamato il costruttore della classe. Quindi, nella riga

Scatola miaScatola1 = new Scatola();

new Scatola() sta chiamando il costruttore Scatola().

Quando non si definisce esplicitamente un costruttore per una classe, Java crea un costruttore di default per la classe. Questo è il motivo per cui la riga di codice vista nelle versioni precedenti di Scatola che non definivano un costruttore, funzionava comunque.

Quando si usa il costruttore di default, tutte le variabili di istanza non inizializzate avranno i loro valori predefiniti, che sono: zero, null e false, rispettivamente per i tipi numerici, i tipi riferimento e i tipi boolean.

Il costruttore di default è spesso sufficiente per classi semplici, ma solitamente non basta per quelle più sofisticate. Una volta definito un costruttore proprio, il costruttore di default non viene più utilizzato.

Costruttori con Parametri

Anche se il costruttore Scatola() nell'esempio precedente inizializza effettivamente un oggetto Scatola, non è molto utile: tutte le scatole hanno le stesse dimensioni.

Quello che serve è un modo per costruire oggetti Scatola con dimensioni diverse. La soluzione più semplice è aggiungere parametri al costruttore. Come si può facilmente intuire, questo lo rende molto più utile. Ad esempio, la versione seguente di Scatola definisce un costruttore parametrizzato che imposta le dimensioni di una scatola secondo i parametri specificati. Prestare particolare attenzione a come vengono creati gli oggetti Scatola.

/*
 * Qui, Scatola usa un costruttore parametrizzato per
 * inizializzare le dimensioni di una scatola.
 */
class Scatola {
    double larghezza;
    double altezza;
    double profondita;

    // Questo è il costruttore per Scatola.
    Scatola(double l, double a, double p) {
        larghezza = l;
        altezza = a;
        profondita = p;
    }

    // calcola e restituisce il volume
    double volume() {
        return larghezza * altezza * profondita;
    }
}
class DimostrazioneScatola {
    public static void main(String[] args) {
        // dichiarare, allocare e inizializzare oggetti Scatola
        Scatola miaScatola1 = new Scatola(10, 20, 15);
        Scatola miaScatola2 = new Scatola(3, 6, 9);

        double volume;

        // ottenere il volume della prima scatola
        volume = miaScatola1.volume();
        System.out.println("Il volume è " + volume);

        // ottenere il volume della seconda scatola
        volume = miaScatola2.volume();
        System.out.println("Il volume è " + volume);
    }
}

L'output di questo programma è mostrato qui:

Il volume è 3000.0
Il volume è 162.0

Come si può vedere, ogni oggetto è inizializzato come specificato nei parametri del suo costruttore. Ad esempio, nella seguente riga,

Scatola miaScatola1 = new Scatola(10, 20, 15);

i valori 10, 20 e 15 sono passati al costruttore Scatola() quando new crea l'oggetto. Così, la copia di miaScatola1 di larghezza, altezza e profondita conterrà rispettivamente i valori 10, 20 e 15.