CodeGym /Java Blog /Random-IT /Costruttori di classi di base
John Squirrels
Livello 41
San Francisco

Costruttori di classi di base

Pubblicato nel gruppo Random-IT
CIAO! L'ultima volta abbiamo parlato di costruttori e abbiamo imparato molto su di loro. Ora parleremo dei costruttori di classi base .
Costruttori di classi base - 1
Che cos'è una classe base ? Ha a che fare con il fatto che in Java diverse classi possono avere un'origine comune.
Costruttori di classi base - 2
Questa si chiama ereditarietà . Diverse classi figlie possono avere un antenato comune. Ad esempio, immagina di avere una Animalclasse:

public class Animal {
  
   String name;
   int age;
}
Possiamo dichiarare 2 classi figlie: Cate Dog. Questo viene fatto usando la parola chiave extends .

public class Cat extends Animal {

}

public class Dog extends Animal {
  
}
Potremmo trovarlo utile in futuro. Ad esempio, se c'è un compito per catturare i topi, creeremo un Cat oggetto nel nostro programma. Se il compito è inseguire un bastone, allora useremo un Dog oggetto. E se creiamo un programma che simula una clinica veterinaria, funzionerà con la Animal classe (e quindi sarà in grado di curare sia cani che gatti). È molto importante ricordare che quando viene creato un oggetto, viene prima chiamato il costruttore della sua classe base . Solo dopo che il costruttore è terminato il programma esegue il costruttore della classe corrispondente all'oggetto che stiamo creando. In altre parole, quando si crea un Catoggetto, il Animalcostruttore viene eseguito per primo e solo dopo viene eseguito ilCatcostruttore eseguito . Per vedere questo, aggiungi un po' di output della console ai costruttori Cate Animal.

public class Animal {

   public Animal() {
       System.out.println("Animal constructor executed");
   }
}


public class Cat extends Animal {

   public Cat() {
       System.out.println("Cat constructor executed!");
   }

   public static void main(String[] args) {
       Cat cat = new Cat();
   }
}
Output della console: Costruttore di animali eseguito Costruttore di gatti eseguito! In effetti, funziona così! Perché? Uno dei motivi è evitare di duplicare i campi condivisi tra le due classi. Ad esempio, ogni animale ha un cuore e un cervello, ma non tutti gli animali hanno una coda. Potremmo dichiarare i campi cervello e cuore , che sono comuni a tutti gli animali, nella Animalclasse genitore, e un campo coda nella Catsottoclasse. . Ora dichiareremo un Catcostruttore di classe che accetta argomenti per tutti e 3 i campi.

public class Cat extends Animal {

   String tail;

   public Cat(String brain, String heart, String tail) {
       this.brain = brain;
       this.heart = heart;
       this.tail = tail;
   }

   public static void main(String[] args) {
       Cat cat = new Cat("Brain", "Heart", "Tail");
   }
}
Nota: il costruttore funziona correttamente anche se la Catclasse non ha campi brain e heart . Questi campi sono "ereditati" dalla Animalclasse base. La classe che eredita ha accesso ai campi della classe base , quindi sono visibili nella nostra Catclasse. Di conseguenza, non è necessario duplicare questi campi nella Catclasse. Possiamo prenderli dalla Animalclasse. Inoltre, possiamo chiamare esplicitamente il costruttore della classe base nel costruttore della classe figlia. Una classe base è anche chiamata " superclasse ". Ecco perché Java utilizza la parola chiave super per indicare la classe base. Nell'esempio precedente

public Cat(String brain, String heart, String tail) {
       this.brain = brain;
       this.heart = heart;
       this.tail = tail;
   }
Abbiamo assegnato separatamente ciascun campo nella nostra classe genitore. In realtà non dobbiamo farlo. È sufficiente chiamare il costruttore della classe genitore e passare gli argomenti necessari:

public class Animal {

   String brain;
   String heart;

   public Animal(String brain, String heart) {
       this.brain = brain;
       this.heart = heart;
   }

public class Cat extends Animal {

   String tail;

   public Cat(String brain, String heart, String tail) {
       super(brain, heart);
       this.tail = tail;
   }

   public static void main(String[] args) {
       Cat cat = new Cat("Brain", "Heart", "Tail");
   }
}
Nel Catcostruttore, abbiamo chiamato il Animalcostruttore e passato due campi. Avevamo solo un campo da inizializzare esplicitamente: tail , che non è in Animal. Ricordi che abbiamo detto che il costruttore della classe genitore viene chiamato per primo quando viene creato un oggetto? Ecco perché super() dovrebbe sempre essere il primo in un costruttore! In caso contrario, la logica del costruttore verrà violata e il programma genererà un errore.

public class Cat extends Animal {

   String tail;

   public Cat(String brain, String heart, String tail) {
       this.tail = tail;
       super(brain, heart);// Error!
   }

   public static void main(String[] args) {
       Cat cat = new Cat("Brain", "Heart", "Tail");
   }
}
Il compilatore sa che quando viene creato un oggetto di una classe figlia, viene chiamato per primo il costruttore della classe base. E se provi a modificare manualmente questo comportamento, il compilatore non lo consentirà.

Come si crea un oggetto

In precedenza abbiamo esaminato un esempio con una classe base e genitore: Animale Cat. Usando queste due classi come esempi, esamineremo ora il processo di creazione di un oggetto e di inizializzazione delle variabili. Sappiamo che esistono variabili statiche e di istanza (non statiche) . Sappiamo anche che la Animalclasse base ha variabili e la Catclasse figlia ha le sue. Per chiarezza, aggiungeremo una variabile statica ciascuna alle classi Animale Cat. La variabile animalCount nella Animalclasse rappresenterà il numero totale di specie animali sulla Terra e il catCountvariabile indicherà il numero di specie di gatti. Inoltre, assegneremo valori iniziali a tutte le variabili non statiche in entrambe le classi (che verranno poi modificate nel costruttore).

public class Animal {

   String brain = "Initial value of brain in the Animal class";
   String heart = "Initial value of heart in the Animal class";

   public static int animalCount = 7700000;

   public Animal(String brain, String heart) {
       System.out.println("Animal base class constructor is running");
       System.out.println("Have the variables of the Animal class already been initialized?");
       System.out.println("Current value of static variable animalCount = " + animalCount);
       System.out.println("Current value of brain in the Animal class = " + this.brain);
       System.out.println("Current value of heart in the Animal class = " + this.heart);
       System.out.println("Have the variables of the Cat class already been initialized?");
       System.out.println("Current value of static variable catCount = " + Cat.catCount);

       this.brain = brain;
       this.heart = heart;
       System.out.println("Animal base class constructor is done!");
       System.out.println("Current value of brain = " + this.brain);
       System.out.println("Current value of heart = " + this.heart);
   }
}

public class Cat extends Animal {

   String tail = "Initial value of tail in the Cat class";

   static int catCount = 37;

   public Cat(String brain, String heart, String tail) {
       super(brain, heart);
       System.out.println("The cat class constructor has started (The Animal constructor already finished)");
       System.out.println("Current value of static variable catCount = " + catCount);
       System.out.println("Current value of tail = " + this.tail);
       this.tail = tail;
       System.out.println("Current value of tail = " + this.tail);
   }

   public static void main(String[] args) {
       Cat cat = new Cat("Brain", "Heart", "Tail");
   }
}
Quindi stiamo creando una nuova istanza della Catclasse, che eredita Animal. Abbiamo aggiunto un output dettagliato della console per vedere cosa sta succedendo e in quale ordine. Questo è ciò che verrà visualizzato quando Catviene creato un oggetto: Il costruttore della classe base Animal è in esecuzione Le variabili della classe Animal sono già state inizializzate? Valore attuale della variabile statica animalCount = 7700000 Valore attuale del cervello nella classe Animale = Valore iniziale del cervello nella classe Animale Valore attuale del cuore nella classe Animale = Valore iniziale del cuore nella classe Animale Sono già presenti le variabili della classe Gatto stato inizializzato? Valore corrente della variabile statica catCount = 37 Il costruttore della classe base animale è terminato! Valore corrente di brain = Brain Valore corrente heart = Heart Il costruttore della classe cat è iniziato (il costruttore Animal è già terminato) Valore corrente della variabile statica catCount = 37 Valore corrente di tail = Valore iniziale di tail nella classe Cat Valore corrente di tail = Coda Quindi, ora possiamo vedere chiaramente l'ordine di inizializzazione delle variabili e le chiamate al costruttore quando viene creato un nuovo oggetto:
  1. Le variabili statiche della classe base ( Animal) vengono inizializzate. Nel nostro caso, la variabile animalCountAnimal della classe è impostata su 7700000.

  2. Le variabili statiche della classe figlia ( Cat) vengono inizializzate.

    Nota: siamo ancora all'interno del Animalcostruttore e abbiamo già visualizzato:

    Il costruttore della classe base Animal è in esecuzione
    Le variabili della classe Animal sono già state inizializzate?
    Valore attuale della variabile statica animalCount = 7700000
    Valore attuale del cervello nella classe Animale = Valore iniziale del cervello nella classe Animale
    Valore attuale del cuore nella classe Animale = Valore iniziale del cuore nella classe Animale
    Sono già presenti le variabili della classe Gatto stato inizializzato?
    Valore corrente della variabile statica catCount = 37


  3. Quindi vengono inizializzate le variabili non statiche della classe base . Abbiamo assegnato loro in modo specifico i valori iniziali, che vengono poi sostituiti nel costruttore. Il costruttore Animale non è ancora terminato, ma sono già stati assegnati i valori iniziali di cervello e cuore:

    Il costruttore della classe base Animal è in esecuzione
    Le variabili della classe Animal sono già state inizializzate?
    Valore corrente della variabile statica animalCount = 7700000
    Valore corrente del cervello nella classe Animale = Valore iniziale del cervello nella classe Animale
    Valore corrente del cuore nella classe Animale = Valore iniziale del cuore nella classe Animale


  4. Viene avviato il costruttore della classe di base .
    Ci siamo già convinti che questo passo è il quarto: nei primi tre passi all'inizio del Animalcostruttore, a molte variabili sono già stati assegnati dei valori.


  5. I campi non statici della classe figlio ( Cat) vengono inizializzati.
    Ciò accade prima che il Catcostruttore inizi a essere eseguito.
    Quando inizia a funzionare, la variabile tail ha già un valore:

    Il costruttore della classe cat è stato avviato (il costruttore Animal è già terminato) Valore corrente della variabile statica catCount = 37 Valore corrente di tail = Valore iniziale di tail nella classe Cat


  6. CatViene chiamato il costruttore della classe figlia

    Ed è così che si crea un oggetto in Java!

    Devo dire che non siamo grandi fan dell'apprendimento meccanico, ma è meglio memorizzare l'ordine dell'inizializzazione delle variabili e delle chiamate al costruttore .

    Ciò aumenterà notevolmente la tua comprensione del flusso del programma e dello stato dei tuoi oggetti in un determinato momento.

    Inoltre, molte classi non usano l'ereditarietà. In questo caso, i passaggi relativi alla classe base non si applicano.

Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION