Parola chiave super di Java spiegata: costruttori, metodi e campi (con esempi)

translated markdown.## 1. Relazione tra ereditarietà e super

Per comprendere la parola chiave super di Java, dovresti prima capire l’ereditarietà.
super non è qualcosa che si memorizza isolatamente—il suo significato diventa chiaro una volta che vedi come una classe figlia e una classe genitore lavorano insieme.

In questa sezione imparerai cos’è l’ereditarietà e perché super esiste, usando spiegazioni per principianti ed esempi di codice semplici.

目次

1.1 Cos’è l’ereditarietà in Java? (Nozioni di base di extends)

In Java, l’ereditarietà ti permette di creare una nuova classe basata su una classe esistente.

  • Classe genitore (superclasse) : la classe base
  • Classe figlia (sottoclasse) : la classe che eredita dalla classe genitore

Quando una classe figlia estende una classe genitore, può riutilizzare i campi e i metodi del genitore senza riscriverli.

Sintassi di base dell’ereditarietà (extends)

class Parent {
    void hello() {
        System.out.println("Hello from Parent");
    }
}

class Child extends Parent {
}

Qui, Child eredita il metodo hello() da Parent.

public class Main {
    public static void main(String[] args) {
        Child child = new Child();
        child.hello(); // calling a method inherited from Parent
    }
}

Output:

Hello from Parent

Quindi, anche se Child non definisce hello(), può comunque chiamarlo perché l’ha ereditato.

1.2 Perché abbiamo bisogno di super?

A questo punto, potresti pensare:

“Se la classe figlia eredita già tutto dal genitore, perché dovremmo aver bisogno di super?”

In molti casi, non è necessario scrivere super esplicitamente.
Tuttavia, super diventa necessario quando vuoi accedere chiaramente alla versione del genitore di qualcosa.

Le situazioni comuni includono:

  • La classe figlia sovrascrive un metodo, ma vuoi comunque chiamare la versione del genitore
  • La classe figlia e la classe genitore hanno campi con lo stesso nome
  • È necessario chiamare un costruttore specifico del genitore usando argomenti

In breve:

super è usato quando vuoi riferirti esplicitamente al lato della classe genitore.

1.3 Sovrascrittura e super (Mantenere il comportamento del genitore)

Uno dei motivi più comuni per usare super è la sovrascrittura di metodi.

La sovrascrittura significa che la classe figlia fornisce la propria versione di un metodo che esiste già nella classe genitore.

Esempio: sovrascrivere un metodo

class Parent {
    void greet() {
        System.out.println("Parent: Hello!");
    }
}

class Child extends Parent {
    @Override
    void greet() {
        System.out.println("Child: Hi!");
    }
}

Ora, se chiami greet() su un oggetto Child:

public class Main {
    public static void main(String[] args) {
        Child child = new Child();
        child.greet();
    }
}

Output:

Child: Hi!

Viene eseguita la versione della figlia, perché la sovrascrittura dà priorità alla classe figlia.

Chiamare la versione del genitore con super.greet()

A volte non vuoi sostituire completamente il comportamento del genitore—vuoi solo aggiungere logica extra.

È qui che super.method() è utile:

class Parent {
    void greet() {
        System.out.println("Parent: Hello!");
    }
}

class Child extends Parent {
    @Override
    void greet() {
        super.greet(); // call parent version
        System.out.println("Child: Hi!");
    }
}

Output:

Parent: Hello!
Child: Hi!

Questo è un modello molto pratico:

  • La classe genitore gestisce il comportamento comune
  • La classe figlia aggiunge comportamento personalizzato

1.4 Quando genitore e figlia hanno lo stesso nome di campo

Un’altra situazione in cui super è importante è quando una classe genitore e una classe figlia hanno campi con lo stesso nome.

Esempio:

class Parent {
    int value = 100;
}

class Child extends Parent {
    int value = 200;

    void printValue() {
        System.out.println(value);
    }
}

Qui, value si riferisce al campo della classe figlia, quindi l’output sarà:

200

.Se vuoi accedere al campo della classe genitore, usa super.value:

class Child extends Parent {
    int value = 200;

    void printValue() {
        System.out.println(value);       // child value
        System.out.println(super.value); // parent value
    }
}

Output:

200
100

Punto chiave:

  • value → campo della classe figlia
  • super.value → campo della classe genitore

1.5 Cosa significa davvero super (Definizione semplice)

Ora puoi riassumere super così:

super è una parola chiave che ti permette di accedere esplicitamente alla versione della classe genitore di campi, metodi e costruttori.

Se devi ricordare una sola frase, ricordala così:

super significa “usa la versione della classe genitore”.

Nella sezione successiva imparerai i 3 modi più importanti di usare super, con esempi chiari per ciascuno.

2. Come usare super (3 pattern fondamentali)

Ora che hai capito cosa significa super, concentriamoci su come viene effettivamente usato in Java.

Nel codice reale, super appare in tre pattern principali:

  1. Chiamare un costruttore del genitore (super() / super(args…))
  2. Chiamare un metodo del genitore (super.method())
  3. Accedere a un campo del genitore (super.field)

Una volta appresi questi tre, super diventa molto facile da riconoscere e usare correttamente.

2.1 Chiamare un costruttore del genitore (super() / super(args…))

2.1.1 Rapido ripasso: cos’è un costruttore?

Un costruttore è un metodo speciale che viene eseguito quando crei un oggetto.

class Person {
    Person() {
        System.out.println("Person constructor");
    }
}

I costruttori servono per l’inizializzazione, ad esempio per impostare i campi.

2.1.2 Nell’ereditarietà, il costruttore del genitore viene eseguito per primo

Nell’ereditarietà Java, la creazione di un oggetto figlio inizia sempre inizializzando prima la parte del genitore.

Ciò significa:

Costruttore del genitore → Costruttore della figlia

Esempio:

class Parent {
    Parent() {
        System.out.println("Parent constructor");
    }
}

class Child extends Parent {
    Child() {
        System.out.println("Child constructor");
    }
}

public class Main {
    public static void main(String[] args) {
        new Child();
    }
}

Output:

Parent constructor
Child constructor

Anche se non abbiamo scritto super(), il costruttore del genitore è stato comunque eseguito.

2.1.3 super() viene inserito automaticamente (quando possibile)

Se la classe genitore ha un costruttore senza argomenti, Java inserisce automaticamente questa riga all’inizio del costruttore della figlia:

super();

Quindi questi due costruttori sono effettivamente equivalenti:

Child() {
    System.out.println("Child constructor");
}
Child() {
    super(); // implicitly inserted by the compiler
    System.out.println("Child constructor");
}

2.1.4 Quando il genitore ha solo un costruttore parametrizzato

Questo è uno degli errori più comuni per i principianti.

Se la classe genitore non ha un costruttore senza argomenti, Java non può inserire super() automaticamente.

Esempio (causerà un errore di compilazione):

class Parent {
    Parent(int x) {
        System.out.println("Parent: " + x);
    }
}

class Child extends Parent {
    Child() {
        System.out.println("Child created");
    }
}

Perché fallisce:

  • Il compilatore tenta di inserire super();
  • Ma Parent() non esiste

✅ Correzione: chiamare esplicitamente il costruttore corretto del genitore

class Child extends Parent {
    Child() {
        super(10);
        System.out.println("Child created");
    }
}

Output:

Parent: 10
Child created

2.1.5 super(...) deve essere la prima riga nel costruttore

Java richiede che super(...) sia la prima istruzione in un costruttore.

❌ Errato:

Child() {
    System.out.println("Something first");
    super(10); // compile error
}

✅ Corretto:

Child() {
    super(10);
    System.out.println("Child logic");
}

Motivo:

  • Il genitore deve essere inizializzato prima che il figlio possa eseguire in sicurezza la propria logica.

2.2 Chiamare un Metodo del Genitore (super.method())

Un altro caso d’uso molto comune è chiamare il metodo del genitore dopo averlo sovrascritto.

2.2.1 Esempio base

class Parent {
    void show() {
        System.out.println("Parent show()");
    }
}

class Child extends Parent {
    @Override
    void show() {
        System.out.println("Child show()");
    }

    void test() {
        super.show(); // parent version
        show();       // child version
    }
}

public class Main {
    public static void main(String[] args) {
        new Child().test();
    }
}

Output:

Parent show()
Child show()

2.2.2 Quando è utile?

super.method() è utile quando:

  • Il metodo del genitore contiene logica comune
  • Il metodo del figlio deve estendere il comportamento invece di sostituirlo
  • Vuoi evitare di copiare‑incollare la logica del genitore nel figlio

Esempio:

class Parent {
    void process() {
        System.out.println("Common processing");
    }
}

class Child extends Parent {
    @Override
    void process() {
        super.process();
        System.out.println("Child-specific processing");
    }
}

Questo schema mantiene il tuo codice pulito e manutenibile.

2.3 Accedere a un Campo del Genitore (super.field)

I campi funzionano in modo simile. Se sia il genitore che il figlio hanno un campo con lo stesso nome, il campo del figlio nasconde quello del genitore.

Esempio:

class Parent {
    int value = 100;
}

class Child extends Parent {
    int value = 200;

    void print() {
        System.out.println(value);       // child field
        System.out.println(super.value); // parent field
    }
}

public class Main {
    public static void main(String[] args) {
        new Child().print();
    }
}

Output:

200
100

2.3.1 Dovresti farlo in progetti reali?

Di solito, avere lo stesso nome di campo in genitore e figlio non è una buona idea perché può confondere i lettori.

Tuttavia, può succedere quando:

  • Stai mantenendo codice legacy
  • Sei costretto a rispettare un design di classe genitore esistente
  • Devi differenziare chiaramente i valori genitore vs figlio

In quei casi, super.field è lo strumento corretto.

2.4 Riepilogo dei 3 pattern

Puoi ricordare super così:

  • super() / super(args…) → chiama il costruttore del genitore
  • super.method() → chiama il metodo del genitore
  • super.field → accede al campo del genitore

Nella sezione successiva approfondiremo con esempi di codice pratici così potrai vedere chiaramente come questi pattern si comportano durante l’esecuzione.

3. Esempi Pratici per Padroneggiare super

A questo punto, conosci già i tre modi fondamentali per usare super.
Ora facciamo in modo che questa conoscenza rimanga passando in rassegna esempi pratici.

Questa sezione si concentra su:

  • Ordine di esecuzione
  • Cosa viene chiamato e perché
  • Come super modifica il comportamento nel codice reale

3.1 Esempio 1: Ordine di chiamata del costruttore (Genitore → Figlio)

La regola più importante da ricordare:

Quando si crea un oggetto figlio, Java inizializza sempre prima la parte del genitore.

class Parent {
    Parent() {
        System.out.println("Parent constructor");
    }
}

class Child extends Parent {
    Child() {
        super(); // optional here, but allowed
        System.out.println("Child constructor");
    }
}

public class Main {
    public static void main(String[] args) {
        new Child();
    }
}

Output:

Parent constructor
Child constructor

Punto chiave:
Anche se rimuovi super(), il risultato è lo stesso (purché il genitore abbia un costruttore senza argomenti).

3.2 Esempio 2: Il genitore ha solo un costruttore parametrizzato

Se la classe genitore non ha un costruttore senza argomenti, il figlio deve chiamare esplicitamente quello corretto.

class Parent {
    Parent(String name) {
        System.out.println("Parent: " + name);
    }
}

.class Child extends Parent {
    Child() {
        super("Taro");
        System.out.println("Child created");
    }
}

public class Main {
    public static void main(String[] args) {
        new Child();
    }
}

Output:

Parent: Taro
Child created

Key point:
If you forget super("Taro"), Java tries to insert super() automatically and fails.

3.3 Example 3: Calling a parent method after overriding (super.method())

This is one of the most useful patterns in real projects.

class Parent {
    void greet() {
        System.out.println("Hello from Parent");
    }
}

class Child extends Parent {
    @Override
    void greet() {
        super.greet(); // call parent behavior
        System.out.println("Hello from Child");
    }
}

public class Main {
    public static void main(String[] args) {
        new Child().greet();
    }
}

Output:

Hello from Parent
Hello from Child

Key point:
You can extend parent behavior without rewriting it.

3.4 Example 4: Accessing a hidden parent field (super.field)

If parent and child both define a field with the same name, the child version hides the parent version.

class Parent {
    int value = 100;
}

class Child extends Parent {
    int value = 200;

    void printValues() {
        System.out.println("Child value: " + value);
        System.out.println("Parent value: " + super.value);
    }
}

public class Main {
    public static void main(String[] args) {
        new Child().printValues();
    }
}

Output:

Child value: 200
Parent value: 100

Key point:

  • value refers to the child’s field
  • super.value refers to the parent’s field

3.5 Example 5: Calling both parent and child versions clearly

This is a great example to remove confusion.

class Parent {
    void show() {
        System.out.println("Parent show()");
    }
}

class Child extends Parent {
    @Override
    void show() {
        System.out.println("Child show()");
    }

    void test() {
        super.show(); // parent version
        this.show();  // child version (same as just calling show())
    }
}

public class Main {
    public static void main(String[] args) {
        new Child().test();
    }
}

Output:

Parent show()
Child show()

Key point:

  • super.show() = parent
  • this.show() = child

3.6 A realistic example: shared logic in the parent class

In real applications, parent classes often contain common logic such as logging, validation, or setup steps.

class BaseService {
    void execute() {
        System.out.println("[LOG] Start execution");
    }
}

class UserService extends BaseService {
    @Override
    void execute() {
        super.execute(); // reuse shared behavior
        System.out.println("UserService logic running...");
    }
}

public class Main {
    public static void main(String[] args) {
        new UserService().execute();
    }
}

Output:

[LOG] Start execution
UserService logic running...

Why this is useful:

  • You avoid duplicating common behavior
  • The child focuses only on what’s unique
  • Your code becomes easier to maintain

3.7 Section summary

From these examples, you should remember:

  • Parent constructors run before child constructors
  • super(args...) is required if the parent has no no-arg constructor
  • super.method() is perfect for reusing and extending behavior
  • super.field helps when parent and child fields share the same name

Next, we’ll clarify one of the most confusing topics for beginners:

What’s the difference between this and super?

4. Difference Between this and super

When learning Java’s super, you will almost always see this at the same time.
Both are reference keywords, so it’s easy for beginners to mix them up.

In this section, you’ll learn:

  • Cosa significa this
  • Cosa significa super
  • Come usarli correttamente con campi, metodi e costruttori

4.1 this si riferisce all’oggetto corrente (l’istanza figlia)

this significa:

“l’istanza corrente dell’oggetto”

È più comunemente usato quando il nome di un campo e il nome di un parametro del costruttore sono gli stessi.

class User {
    String name;

    User(String name) {
        this.name = name; // field = parameter
    }
}

Qui:

  • name (lato destro) è il parametro del costruttore
  • this.name (lato sinistro) è il campo dell’istanza

Quindi this ti aiuta a evitare confusioni.

4.2 super si riferisce al lato della classe genitore

super si riferisce alla parte della classe genitore (superclasse) dell’oggetto corrente.

Significa:

“usa la versione della classe genitore”

Lo usi principalmente quando vuoi accedere ai membri della classe genitore che sono nascosti o sovrascritti.

4.3 Il modo più semplice per ricordare la differenza

Un modo adatto ai principianti per memorizzare:

  • thisil lato della classe figlia
  • superil lato della classe genitore

Non sono due oggetti diversi.
Sono due “viste” diverse dello stesso oggetto.

4.4 Uso di this e super con i campi

Se sia il genitore che il figlio definiscono un campo con lo stesso nome, puoi scegliere chiaramente quale vuoi.

class Parent {
    int value = 100;
}

class Child extends Parent {
    int value = 200;

    void print() {
        System.out.println(this.value);  // child field
        System.out.println(super.value); // parent field
    }
}

public class Main {
    public static void main(String[] args) {
        new Child().print();
    }
}

Output:

200
100

Punto chiave:

  • this.value = campo del figlio
  • super.value = campo del genitore

Inoltre, in Java, this è spesso opzionale:

System.out.println(value);

è lo stesso di:

System.out.println(this.value);

4.5 Uso di this e super con i metodi

I metodi sono l’area più comune in cui la differenza tra this e super è importante—soprattutto con l’override.

class Parent {
    void show() {
        System.out.println("Parent show()");
    }
}

class Child extends Parent {
    @Override
    void show() {
        System.out.println("Child show()");
    }

    void test() {
        this.show();   // child method (same as show())
        super.show();  // parent method
    }
}

public class Main {
    public static void main(String[] args) {
        new Child().test();
    }
}

Output:

Child show()
Parent show()

Punto chiave:

  • this.show() → versione del figlio
  • super.show() → versione del genitore

4.6 Costruttori: this() vs super()

Questa è una delle parti più confuse per i principianti, ma è molto importante.

  • this() chiama un altro costruttore nella stessa classe
  • super() chiama un costruttore nella classe genitore

4.6.1 Esempio di this() (chaining di costruttori nella stessa classe)

class User {
    String name;
    int age;

    User() {
        this("NoName", 0); // call another constructor
    }

    User(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

Questo è utile perché evita di ripetere la logica di inizializzazione.

4.6.2 Esempio di super() (chiamata al costruttore del genitore)

class Parent {
    Parent() {
        System.out.println("Parent constructor");
    }
}

class Child extends Parent {
    Child() {
        super(); // initialize parent
        System.out.println("Child constructor");
    }
}

Output:

Parent constructor
Child constructor

4.7 Non è possibile usare this() e super() insieme

Molti principianti provano qualcosa del genere:

Child() {
    this(1);
    super(); // error
}

Questo non è consentito.

Motivo:

  • Sia this() che super() devono essere la prima riga nel costruttore
  • Solo uno dei due può essere il primo

Quindi devi sceglierne uno.

4.8 Promemoria importante: super non crea un nuovo oggetto

super non crea un oggetto genitore separato.

Invece:

  • this = oggetto corrente visualizzato come figlio
  • super = stesso oggetto visualizzato come genitore

Ecco perché super è meglio considerarlo una parola‑chiave di riferimento, non un creatore di oggetti.

4.9 Riepilogo della sezione

  • this si riferisce all’oggetto corrente (lato figlio)
  • super si riferisce al lato della classe genitore
  • this() chiama un altro costruttore nella stessa classe
  • super() chiama un costruttore nella classe genitore
  • this() e super() non possono essere usati insieme

Successivamente, tratteremo gli errori comuni e i pattern di errore in modo che tu possa evitare le trappole più frequenti per i principianti.

5. Errori comuni e insidie (come evitare gli errori)

La parola‑chiave super di Java è potente, ma è anche facile da usare in modo errato—soprattutto quando stai ancora imparando l’ereditarietà e i costruttori.

In questa sezione imparerai gli errori più comuni che commettono i principianti e come correggerli rapidamente.

5.1 Scrivere super(...) nel posto sbagliato (regola del costruttore)

Una delle regole più importanti:

super(...) deve essere la prima istruzione all’interno di un costruttore.

❌ Sbagliato (errore di compilazione):

class Parent {
    Parent(int x) {}
}

class Child extends Parent {
    Child() {
        System.out.println("Do something first");
        super(10); // ERROR: must be first line
    }
}

✅ Corretto:

class Child extends Parent {
    Child() {
        super(10);
        System.out.println("Child logic");
    }
}

Perché?
Perché la parte genitore dell’oggetto deve essere inizializzata prima che venga eseguita la logica del figlio.

5.2 Dimenticare super(args...) quando il genitore non ha un costruttore senza argomenti

Se la classe genitore ha solo un costruttore parametrizzato, Java non può inserire automaticamente super().

❌ Sbagliato:

class Parent {
    Parent(String name) {}
}

class Child extends Parent {
    Child() {
        // compiler tries to insert super() here -> ERROR
    }
}

✅ Corretto:

class Child extends Parent {
    Child() {
        super("Taro");
    }
}

Questo è un errore di compilazione molto comune per i principianti, quindi controlla sempre i costruttori del genitore.

5.3 Tentare di usare sia this() sia super() nello stesso costruttore

I principianti spesso pensano:

“Voglio chiamare un altro costruttore E il costruttore del genitore.”

Ma Java non lo consente.

❌ Sbagliato:

class Parent {
    Parent() {}
}

class Child extends Parent {
    Child() {
        this(1);
        super(); // ERROR
    }

    Child(int x) {}
}

Motivo:

  • this() e super() devono entrambi essere la prima riga
  • Solo uno dei due può essere per primo

Quindi devi progettare i tuoi costruttori in modo che ne venga usato solo uno direttamente.

5.4 Tentare di usare super all’interno di un metodo statico

super è legato all’istanza corrente dell’oggetto, quindi non funziona nei metodi statici.

❌ Sbagliato (concettualmente):

class Parent {
    void hello() {}
}

class Child extends Parent {
    static void test() {
        super.hello(); // ERROR
    }
}

Punto chiave:

  • I metodi statici appartengono alla classe, non a un’istanza
  • super si riferisce alla parte genitore di un’istanza

Perciò Java impedisce questa operazione.

5.5 Confondere super con “creare un oggetto genitore”

Alcuni principianti presumono:

“Usare super crea un oggetto genitore separato.”

Non è vero.

super non crea un nuovo oggetto.
Accede semplicemente al lato della classe genitore dello stesso oggetto.

Pensalo così:

  • this = stesso oggetto, vista figlio
  • super = stesso oggetto, vista genitore

5.6 Usare super.field troppo spesso (nascondere i campi è generalmente una cattiva idea)

Sì, super.field esiste—ma nella maggior parte dei progetti reali dovresti evitare di creare campi genitore/figlio con lo stesso nome.

Esempio (design confuso):

class Parent {
    int value = 100;
}

class Child extends Parent {
    int value = 200; // hides parent field
}

Anche se super.value funziona, questo design rende il codice più difficile da leggere e mantenere.

Pratica migliore:

  • Usa nomi di campo diversi
  • Mantieni i campi privati ed esponili tramite metodi (getter)
  • Evita di nascondere i campi a meno che non sia assolutamente necessario

5.7 “Se chiamo super.method(), viene eseguita solo la logica del genitore” (non sempre)

Questo è leggermente più avanzato, ma utile da sapere.

Quando chiami super.method(), chiami sicuramente il metodo del genitore.
Tuttavia, all’interno di quel metodo del genitore, se chiama un altro metodo che il figlio sovrascrive, potrebbe essere eseguita la versione del figlio.

Esempio:

class Parent {
    void a() {
        b(); // calls b()
    }

    void b() {
        System.out.println("Parent b()");
    }
}

class Child extends Parent {
    @Override
    void b() {
        System.out.println("Child b()");
    }
}

public class Main {
    public static void main(String[] args) {
        Child c = new Child();
        c.a();
    }
}

Output:

Child b()

Anche se a() è nel genitore, chiama b(), e b() è sovrascritto nel figlio.

Conclusione per i principianti:
super.method() chiama la versione del genitore di quel metodo, ma le chiamate a metodi all’interno di esso possono comunque seguire le regole di overriding.

5.8 Checklist veloce (per evitare errori da principianti)

Prima di usare super, verifica questi punti:

  • Il super(...) è la prima riga nel costruttore?
  • La classe genitore ha un costruttore senza argomenti?
  • Stai cercando di usare sia this() che super()?
  • Stai usando super all’interno di un metodo statico?
  • Stai nascondendo campi con lo stesso nome inutilmente?

6. Conclusione (Punti Chiave)

In questo articolo, hai imparato cos’è la parola chiave super di Java, perché esiste e come usarla correttamente nel codice reale.

Ricapitoliamo tutto con i punti più importanti da ricordare.

6.1 Cosa significa super in Java?

super è una parola chiave che ti permette di accedere esplicitamente alla parte della classe genitore (superclasse) di un oggetto.

Viene principalmente usato nell’ereditarietà (extends) quando vuoi fare riferimento alla versione genitore di:

  • costruttori
  • metodi
  • campi

In termini semplici:

super significa “usa la versione della classe genitore.”

6.2 I 3 modi più importanti per usare super

Puoi memorizzare super in questi tre schemi:

1) Chiamare il costruttore del genitore

  • super()
  • super(args...)

Questo è usato quando è necessario inizializzare correttamente la classe genitore, specialmente se il genitore richiede argomenti.

2) Chiamare il metodo del genitore

  • super.method()

Questo è utile quando sovrascrivi un metodo ma vuoi comunque riutilizzare il comportamento del genitore.

3) Accedere al campo del genitore

  • super.field

Questo è usato quando sia il genitore che il figlio hanno un campo con lo stesso nome e vuoi riferirti chiaramente a quello del genitore.

6.3 this vs super (il modo più semplice per capirlo)

Molti principianti confondono queste due parole chiave, ma la differenza è semplice:

  • this → l’oggetto corrente (visuale lato figlio)
  • super → la visuale lato genitore dello stesso oggetto

Non rappresentano due oggetti diversi.

6.4 La maggior parte degli errori avviene intorno ai costruttori

Se vuoi evitare gli errori più comuni, ricorda queste regole:

  • super(...) deve essere la prima riga all’interno di un costruttore
  • Se il genitore non ha un costruttore senza argomenti, devi scrivere super(args...)
  • Non puoi usare this() e super() insieme nello stesso costruttore
  • super non funziona nei metodi statici

6.5 Conclusione finale: super ti aiuta a riutilizzare ed estendere in modo sicuro la logica del genitore

Il vero potere di super è che ti permette di:

  • mantenere la logica condivisa nella classe genitore
  • estendere il comportamento nella classe figlio
  • evitare di copiare‑incollare codice
  • rendere l’ereditarietà più pulita e più facile da mantenere

Se ricordi una sola frase da questo intero articolo, ricordala:

super è la parola chiave da usare quando vuoi la versione della classe genitore.

7. FAQ (Domande Frequenti)

Ecco le domande più comuni che i principianti pongono quando imparano la parola chiave super di Java.
Se ti senti ancora insicuro su alcune parti, questa sezione dovrebbe chiarire le cose rapidamente.

7.1 Quando dovrei usare super in Java?

Usi tipicamente super in queste situazioni:

  • Quando vuoi chiamare un costruttore del genitore ( super() / super(args...) )
  • Quando sovrascrivi un metodo ma vuoi ancora chiamare il metodo del genitore ( super.method() )
  • Quando il genitore e il figlio hanno lo stesso nome di campo e vuoi il campo del genitore ( super.field )

Per i principianti, il caso più comune e utile è:

sovrascrivere un metodo e chiamare la logica del genitore usando super.method().

7.2 Cosa succede se non scrivo super()?

Se la classe genitore ha un costruttore senza argomenti, Java inserisce automaticamente:

super();

all’inizio del costruttore del figlio.

Quindi in molti casi, non è necessario scriverlo manualmente.

Tuttavia, se la classe genitore non ha un costruttore senza argomenti, il codice fallirà a meno che tu non chiami esplicitamente quello corretto con argomenti.

7.3 Qual è la differenza tra super() e this()?

Chiamano costruttori diversi:

  • super() → chiama un costruttore nella classe genitore
  • this() → chiama un costruttore nella stessa classe

Idea di esempio:

  • Usa this() per ridurre il codice duplicato nei costruttori
  • Usa super() per inizializzare correttamente la parte genitore dell’oggetto

7.4 Posso usare sia this() che super() nello stesso costruttore?

No, non puoi.

Motivo:

  • Sia this() che super() devono essere la prima istruzione nel costruttore
  • Solo un’istruzione può essere la prima

Quindi Java ti costringe a sceglierne una.

7.5 Posso usare super all’interno di un metodo statico?

No (in generale).

super è relativo all’istanza dell’oggetto corrente, ma i metodi statici appartengono alla classe stessa e non hanno un riferimento a un’istanza.

È per questo che l’uso di super nei metodi statici risulta in un errore di compilazione.

7.6 super crea un nuovo oggetto genitore?

No.

super non crea alcun nuovo oggetto.

Accede semplicemente alla vista della classe genitore dello stesso oggetto.

Un modo utile per pensarlo:

  • this = stesso oggetto visto come figlio
  • super = stesso oggetto visto come genitore

7.7 Se chiamo super.method(), esegue sempre solo la logica del genitore?

super.method() chiama sempre la versione del genitore di quel metodo.

Tuttavia, se il metodo del genitore chiama internamente un altro metodo che il figlio sovrascrive, allora la versione del figlio potrebbe essere eseguita a causa delle regole di overriding di Java.

Lezione per principianti:

super.method() chiama la versione del genitore, ma le chiamate di metodo al suo interno potrebbero ancora essere influenzate dall’overriding.

7.8 Dovrei usare super.field spesso?

Di solito, no.

Se hai frequentemente bisogno di super.field, potrebbe significare che il tuo design è confuso perché il genitore e il figlio condividono lo stesso nome di campo.

Nei progetti reali, è meglio evitare la nascondimento dei campi a meno che tu non abbia un motivo forte (come codice legacy o vincoli esterni).

7.9 super può essere usato con le interfacce?

Nell’ereditarietà normale (extends), super si riferisce alla classe genitore.

Tuttavia, Java permette anche una sintassi speciale per chiamare un metodo predefinito di un’interfaccia:

InterfaceName.super.method();

Questo è più avanzato, quindi se sei un principiante, concentrati prima su:

  • ereditarietà di classe
  • super() / super.method() / super.field

7.10 Qual è il modo più veloce per padroneggiare super?

Un percorso di apprendimento semplice:

  1. Scrivi una classe genitore/figlio di base e conferma l’ordine dei costruttori
  2. Sovrascrivi un metodo e chiama super.method()
  3. Confronta this vs super con campi e metodi
  4. Esercitati a correggere errori relativi ai costruttori

La migliore pratica è scrivere piccoli esempi ed eseguirli.