Animal
(animale):
public class Animal {
String name;
int age;
}
Possiamo creare per questo, ad esempio, 2 classi discendenti - Cat
e Dog
. Questo viene fatto utilizzando la parola chiave extends
.
public class Cat extends Animal {
}
public class Dog extends Animal {
}
Questo potrebbe esserci utile in futuro. Ad esempio, se il compito è catturare i topi, creeremo un oggetto nel programma Cat
. Se il compito è correre dietro a un bastone, utilizziamo l'oggetto Dog
. E se creiamo un programma che simula una clinica veterinaria, funzionerà con la classe Animal
(per poter curare sia cani che gatti). È molto importante ricordare per il futuro che quando si crea un oggetto, viene chiamato prima il costruttore della sua classe base e solo successivamente viene chiamato il costruttore della classe stessa, l'oggetto di cui stiamo creando. Cioè, quando si crea un oggetto, Cat
funzionerà prima il costruttore della classe Animal
e solo dopo il costruttore Cat
. Per essere sicuri di ciò, aggiungiamo i costruttori Cat
e Animal
produciamo l'output sulla console.
public class Animal {
public Animal() {
System.out.println("Animal constructor completed");
}
}
public class Cat extends Animal {
public Cat() {
System.out.println("The constructor Cat worked!");
}
public static void main(String[] args) {
Cat cat = new Cat();
}
}
Uscita console:
Отработал конструктор Animal
Отработал конструктор Cat!
In effetti, è così che funziona! Cosa serve? Ad esempio, per evitare di duplicare i campi comuni di due classi. Ad esempio, ogni animale ha un cuore e un cervello, ma non tutti gli animali hanno una coda. Possiamo dichiarare campi comuni a tutti gli animali brain
nella heart
classe genitore Animal
e un campo tail
nella sottoclasse Cat
. Ora creeremo un costruttore per la classe Cat
, dove passeremo 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");
}
}
Fai attenzione:il costruttore funziona correttamente, sebbene la classe Cat
non abbia campi brain
e heart
. Questi campi sono stati “estratti” dalla classe base Animal
. La classe discendente ha accesso ai campi della classe base, quindi Cat
sono visibili nella nostra classe. Pertanto, non abbiamo bisogno Cat
di duplicare questi campi nella classe: possiamo prenderli dalla classe Animal
. Inoltre, possiamo chiamare esplicitamente il costruttore della classe base nel costruttore della classe discendente. La classe base è anche chiamata “ superclasse ”, motivo per cui Java utilizza la parola chiave super
. 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 presente nella nostra classe genitore. In effetti, non devi farlo. È sufficiente chiamare il costruttore della classe genitore e passargli i parametri 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 costruttore, Cat
abbiamo chiamato il costruttore Animal
e gli abbiamo passato due campi. Dobbiamo solo inizializzare esplicitamente un campo, tail
che Animal
non è presente. Ricordi come abbiamo detto che quando viene creato un oggetto, viene chiamato per primo il costruttore della classe genitore? Quindi, ecco perché la parola super()
dovrebbe sempre venire prima nel costruttore! Altrimenti la logica dei costruttori verrà interrotta 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 si crea un oggetto di una classe discendente, viene chiamato per primo il costruttore della classe base. E se provi a modificare manualmente questo comportamento, non lo consentirà.
Il processo di creazione di un oggetto.
Sopra abbiamo visto un esempio con una classe base e genitore -Animal
e Cat
. Ora, utilizzando queste due classi come esempio, esamineremo il processo di creazione di un oggetto e di inizializzazione delle variabili. Sappiamo che le variabili sono statiche e variabili di istanza (non statiche). Sappiamo anche che la classe base Animal
ha le proprie variabili e la classe discendente Cat
ha le proprie. Aggiungiamo una variabile statica alla classe per Animal
chiarezza . Cat
La variabile animalCount
di classe Animal
sarebbe il numero totale di specie animali sulla terra e la variabile catsCount
sarebbe il numero di specie di gatti. Inoltre, assegneremo valori iniziali a tutte le variabili non statiche di entrambe le classi (che poi cambieranno nel costruttore).
public class Animal {
String brain = "The initial value of brain in the Animal class";
String heart = "The initial value of heart in the Animal class";
public static int animalCount = 7700000;
public Animal(String brain, String heart) {
System.out.println("The constructor of the Animal base class is being executed");
System.out.println("Have the variables of the Animal class already been initialized?");
System.out.println("The current value of the static variable animalCount = " + animalCount);
System.out.println("Current value of brain in class Animal = " + this.brain);
System.out.println("Current value of heart in class Animal = " + this.heart);
System.out.println("Have the variables of the Cat class already been initialized?");
System.out.println("The current value of the static variable catsCount = " + Cat.catsCount);
this.brain = brain;
this.heart = heart;
System.out.println("Animal base class constructor completed!");
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 = "The initial value of tail in the Cat class";
static int catsCount = 37;
public Cat(String brain, String heart, String tail) {
super(brain, heart);
System.out.println("The constructor of the Cat class has started (the Animal constructor has already been executed)");
System.out.println("The current value of the static variable catsCount = " + catsCount);
System.out.println("Current value tail = " + this.tail);
this.tail = tail;
System.out.println("Current value tail = " + this.tail);
}
public static void main(String[] args) {
Cat cat = new Cat("Brain", "Heart", "Tail");
}
}
Quindi, creiamo un nuovo oggetto della classe Cat
ereditata da Animal
. Aggiungiamo l'output dettagliato della console al nostro programma per vedere cosa accadrà e in quale ordine. Questo è ciò che verrà visualizzato sulla console come risultato della creazione di un oggetto Cat
:
Выполняется конструктор базового класса Animal
Были ли уже проинициализированы переменные класса Animal?
Текущее meaning статической переменной animalCount = 7700000
Текущее meaning brain в классе Animal = Изначальное meaning brain в классе Animal
Текущее meaning heart в классе Animal = Изначальное meaning heart в классе Animal
Были ли уже проинициализированы переменные класса Cat?
Текущее meaning статической переменной catsCount = 37
Конструктор базового класса Animal завершил работу!
Текущее meaning brain = Мозг
Текущее meaning heart = Сердце
Конструктор класса Cat начал работу (конструктор Animal уже был выполнен)
Текущее meaning статической переменной catsCount = 37
Текущее meaning tail = Изначальное meaning tail в классе Cat
Текущее meaning tail = Хвост
Quindi, ora possiamo vedere chiaramente in quale ordine le variabili vengono inizializzate e i costruttori vengono chiamati quando si crea un nuovo oggetto:
-
Le variabili statiche della classe base ( ) vengono inizializzate
Animal
. Nel nostro caso alla variabileanimalCount
classAnimal
viene assegnato il valore 7700000. -
Le variabili statiche della classe discendente ( ) vengono inizializzate
Cat
. Fai attenzione: siamo ancora all'interno del costruttoreAnimal
e la console dice già:Выполняется конструктор базового класса Animal Были ли уже проинициализированы переменные класса Animal? Текущее meaning статической переменной animalCount = 7700000 Текущее meaning brain в классе Animal = Изначальное meaning brain в классе Animal Текущее meaning heart в классе Animal = Изначальное meaning heart в классе Animal Были ли уже проинициализированы переменные класса Cat? Текущее meaning статической переменной catsCount = 37
-
Successivamente, vengono inizializzate le variabili non statiche della classe base . Abbiamo assegnato loro specificatamente i valori iniziali, che vengono poi modificati in nuovi nel costruttore. Il costruttore
Animal
non ha ancora terminato il suo lavoro, mabrain
sonoheart
già stati assegnati i valori iniziali:Выполняется конструктор базового класса Animal Были ли уже проинициализированы переменные класса Animal? Текущее meaning статической переменной animalCount = 7700000 Текущее meaning brain в классе Animal = Изначальное meaning brain в классе Animal Текущее meaning heart в классе Animal = Изначальное meaning heart в классе Animal
-
Il costruttore della classe base inizia a funzionare .
Abbiamo già visto che questa fase è solo la quarta di seguito: nei primi tre punti, nel momento in cui il costruttore inizia a lavorare,
Animal
a molte variabili sono già stati assegnati dei valori. -
Inizializzazione dei campi non statici di una classe figlia (
Cat
).Succede prima che il designer
Cat
inizi a lavorare.Nel momento in cui ha iniziato a lavorare, la variabile
tail
aveva già un valore:Конструктор класса Cat начал работу (конструктор Animal уже был выполнен) Текущее meaning статической переменной catsCount = 37 Текущее meaning tail = Изначальное meaning tail в классе Cat
-
Viene chiamato il costruttore della classe discendente
Cat
GO TO FULL VERSION