Costruttori in Java: this, overloading ed esempi

Un costruttore in Java inizializza un oggetto nel momento in cui viene creato con new. Ha lo stesso nome della classe, non dichiara un tipo di ritorno e può ricevere parametri. Vediamo esempi con this, controlli sui dati e overloading.

Perché servono i costruttori

Senza controlli iniziali si rischia di ottenere oggetti con campi incoerenti: un libro con zero pagine, un serbatoio con capacità negativa oppure un corso con posti disponibili inferiori a zero. Un buon costruttore crea l’oggetto solo quando i dati iniziali rispettano le regole previste.

Esempio completo: Libro con costruttore e this

class Libro {
    private String titolo;
    private int pagine;

    public Libro(String titolo, int pagine) {
        if (titolo == null || titolo.isBlank()) {
            throw new IllegalArgumentException("Titolo obbligatorio");
        }
        if (pagine <= 0) {
            throw new IllegalArgumentException("Numero di pagine non valido");
        }
        this.titolo = titolo;
        this.pagine = pagine;
    }

    public String descrizione() {
        return titolo + " - " + pagine + " pagine";
    }
}

public class Main {
    public static void main(String[] args) {
        Libro primo = new Libro("Algoritmi", 180);
        Libro secondo = new Libro("Reti", 240);
        System.out.println(primo.descrizione());
        System.out.println(secondo.descrizione());
    }
}

L’istruzione this.titolo = titolo distingue il campo dell’oggetto (this.titolo) dal parametro (titolo). Il costruttore verifica prima i dati, poi inizializza lo stato. Ogni chiamata a new Libro(...) crea una nuova istanza.

Costruttore predefinito: quando viene generato?

Se una classe non dichiara alcun costruttore, Java fornisce un costruttore predefinito senza parametri. Se dichiari anche un solo costruttore, quello predefinito non viene generato automaticamente. Perciò, con la classe dell’esempio precedente, new Libro() produce un errore di compilazione.

Overloading: più costruttori nella stessa classe

class Contatore {
    private int valore;

    public Contatore() {
        this(0);
    }

    public Contatore(int valoreIniziale) {
        if (valoreIniziale < 0) {
            throw new IllegalArgumentException("Valore negativo");
        }
        valore = valoreIniziale;
    }

    public int getValore() {
        return valore;
    }
}

public class Main {
    public static void main(String[] args) {
        Contatore a = new Contatore();
        Contatore b = new Contatore(10);
        System.out.println(a.getValore()); // 0
        System.out.println(b.getValore()); // 10
    }
}

La classe contiene due costruttori con firme diverse, un esempio di overloading. Nel costruttore senza parametri, this(0) richiama l’altro costruttore: deve essere la prima istruzione esplicita del corpo (nelle forme tradizionali della sintassi Java). this(0) è una chiamata a un costruttore, mentre this.valore accede a un campo: i due usi hanno significati diversi.

Costruttore, metodo ordinario e overload: confronto

CaratteristicaCostruttoreMetodo
NomeUguale al nome della classeScelto dal programmatore
Tipo restituitoNessuno, neppure voidTipo o void
RichiamoAlla creazione con new o da altro costruttoreAttraverso una chiamata di metodo
Scopo principaleInizializzare uno stato validoRealizzare un comportamento
Il costruttore non è un normale metodo di istanza.

Come progettare correttamente la costruzione

  1. Individua gli attributi obbligatori dell’oggetto.
  2. Definisci le invarianti iniziali (ad esempio pagine > 0).
  3. Valida i parametri ricevuti e segnala valori non accettabili.
  4. Assegna tutti i campi necessari prima che l’oggetto venga utilizzato.
  5. Usa più costruttori soltanto quando rappresentano alternative di costruzione chiare.

Esercizi sui costruttori

  • Crea una classe Rettangolo che rifiuti base o altezza non positive.
  • Aggiungi a Libro un secondo costruttore con un solo parametro titolo, che assegni un numero di pagine iniziale valido.
  • Spiega perché public void Libro(...) non è un costruttore.
  • Prevedi cosa accade con new Contatore(-2) e indica quale controllo scatta.

Soluzione concettuale: public void Libro(...) dichiara un metodo chiamato Libro, non un costruttore, perché compare il tipo di ritorno void. new Contatore(-2) lancia IllegalArgumentException perché viola il vincolo iniziale.

Nel percorso OOP: Torna all’indice delle lezioni Java · Ripassa classi e oggetti.