

Animal
classe :
public class Animal {
String name;
int age;
}
On peut déclarer 2 classes enfants : Cat
et Dog
. Ceci est fait en utilisant le mot clé extend .
public class Cat extends Animal {
}
public class Dog extends Animal {
}
Nous pourrions trouver cela utile à l'avenir. Par exemple, s'il existe une tâche pour attraper des souris, nous allons créer un Cat
objet dans notre programme. Si la tâche consiste à courir après un bâton, nous utiliserons un Dog
objet. Et si nous créons un programme qui simule une clinique vétérinaire, il fonctionnera avec la Animal
classe (et pourra ainsi traiter aussi bien les chats que les chiens). Il est très important de se rappeler que lorsqu'un objet est créé, le constructeur de sa classe de base est d'abord appelé . Ce n'est qu'après que ce constructeur est terminé que le programme exécute le constructeur de la classe correspondant à l'objet que nous créons. En d'autres termes, lors de la création d'un Cat
objet, le Animal
constructeur est exécuté en premier , et ce n'est qu'ensuite que leCat
constructeur exécuté . Pour voir cela, ajoutez une sortie de console aux constructeurs Cat
et 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();
}
}
Sortie console : Constructeur animal exécuté Constructeur chat exécuté ! En effet, ça marche comme ça ! Pourquoi? L'une des raisons est d'éviter la duplication des champs partagés entre les deux classes. Par exemple, chaque animal a un cœur et un cerveau, mais tous les animaux n'ont pas de queue. Nous pourrions déclarer les champs cerveau et cœur , qui sont communs à tous les animaux, dans la Animal
classe mère, et un champ queue dans la Cat
sous-classe. . Nous allons maintenant déclarer un Cat
constructeur de classe qui prend des arguments pour les 3 champs.
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");
}
}
Remarque : Le constructeur fonctionne correctement même si la Cat
classe n'a pas de champs cerveau et cœur . Ces champs sont "hérités" de la Animal
classe de base. La classe qui hérite a accès aux champs de la classe de base , ils sont donc visibles dans notre Cat
classe. Par conséquent, nous n'avons pas besoin de dupliquer ces champs dans la Cat
classe. Nous pouvons les retirer de la Animal
classe. De plus, nous pouvons appeler explicitement le constructeur de la classe de base dans le constructeur de la classe enfant. Une classe de base est aussi appelée " superclasse ". C'est pourquoi Java utilise le mot clé super pour indiquer la classe de base. Dans l'exemple précédent
public Cat(String brain, String heart, String tail) {
this.brain = brain;
this.heart = heart;
this.tail = tail;
}
Nous avons attribué séparément chaque champ dans notre classe parent. Nous n'avons pas vraiment à faire ça. Il suffit d'appeler le constructeur de la classe parent et de passer les arguments nécessaires :
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");
}
}
Dans le Cat
constructeur, nous avons appelé le Animal
constructeur et transmis deux champs. Nous n'avions qu'un seul champ à initialiser explicitement : tail , qui n'est pas dans Animal
. Rappelez-vous que nous avons mentionné que le constructeur de la classe parent est appelé en premier lorsqu'un objet est créé ? C'est pourquoi super() doit toujours être le premier dans un constructeur ! Sinon, la logique du constructeur sera violée et le programme générera une erreur.
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");
}
}
Le compilateur sait que lorsqu'un objet d'une classe enfant est créé, le constructeur de la classe de base est appelé en premier. Et si vous essayez de modifier manuellement ce comportement, le compilateur ne le permettra pas.
Comment un objet est créé
Nous avons précédemment regardé un exemple avec une classe de base et une classe parente :Animal
and Cat
. En utilisant ces deux classes comme exemples, nous allons maintenant examiner le processus de création d'un objet et d'initialisation des variables. Nous savons qu'il existe des variables statiques et d'instance (non statiques) . Nous savons également que la Animal
classe de base a des variables et que la Cat
classe enfant a les siennes. Pour plus de clarté, nous ajouterons une variable statique à chacune des classes Animal
et Cat
. La variable animalCountAnimal
de la classe représentera le nombre total d'espèces animales sur Terre, et la variable catCountvariable signifiera le nombre d'espèces de chats. De plus, nous attribuerons des valeurs de départ à toutes les variables non statiques dans les deux classes (qui seront ensuite modifiées dans le constructeur).
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");
}
}
Nous créons donc une nouvelle instance de la Cat
classe, qui hérite de Animal
. Nous avons ajouté une sortie de console détaillée pour voir ce qui se passe et dans quel ordre. Voici ce qui s'affichera lors Cat
de la création d'un objet : Le constructeur de la classe de base Animal est en cours d'exécution Les variables de la classe Animal ont-elles déjà été initialisées ? Valeur actuelle de la variable statique animalCount = 7700000 Valeur actuelle de brain dans la classe Animal = Valeur initiale de brain dans la classe Animal Valeur actuelle de heart dans la classe Animal = Valeur initiale de heart dans la classe Animal Avoir déjà les variables de la classe Cat été initialisé ? La valeur actuelle de la variable statique catCount = 37 Le constructeur de la classe de base animale est terminé ! Valeur actuelle de brain = Brain Valeur actuelle heart = Heart Le constructeur de la classe cat a démarré (le constructeur Animal est déjà terminé) Valeur actuelle de la variable statique catCount = 37 Valeur actuelle de tail = Valeur initiale de tail dans la classe Cat Valeur actuelle de tail = Queue Ainsi, nous pouvons maintenant voir clairement l'ordre d'initialisation des variables et des appels de constructeur lorsqu'un nouvel objet est créé :
- Les variables statiques de la classe de base (
Animal
) sont initialisées. Dans notre cas, laAnimal
variable animalCount de la classe est définie sur 7700000. -
Les variables statiques de la classe enfant (
Cat
) sont initialisées.Remarque : nous sommes toujours dans le
Animal
constructeur et nous avons déjà affiché :Le constructeur de la classe de base Animal est en cours d'exécution
Les variables de la classe Animal ont-elles déjà été initialisées ?
Valeur actuelle de la variable statique animalCount = 7700000
Valeur actuelle de brain dans la classe Animal = Valeur initiale de brain dans la classe Animal
Valeur actuelle de heart dans la classe Animal = Valeur initiale de heart dans la classe Animal
Avoir déjà les variables de la classe Cat été initialisé ?
Valeur actuelle de la variable statique catCount = 37 -
Ensuite, les variables non statiques de la classe de base sont initialisées. Nous leur avons spécifiquement attribué des valeurs initiales, qui sont ensuite remplacées dans le constructeur. Le constructeur Animal n'est pas encore terminé, mais les valeurs initiales de cerveau et de cœur ont déjà été attribuées :
Le constructeur de la classe de base Animal est en cours d'exécution
Les variables de la classe Animal ont-elles déjà été initialisées ?
Valeur actuelle de la variable statique animalCount = 7700000
Valeur actuelle du cerveau dans la classe Animal = Valeur initiale du cerveau dans la classe Animal
Valeur actuelle du cœur dans la classe Animal = Valeur initiale du cœur dans la classe Animal -
Le constructeur de la classe de base démarre.
Nous nous sommes déjà convaincus que cette étape est la quatrième : dans les trois premières étapes au début duAnimal
constructeur, de nombreuses variables ont déjà reçu des valeurs. -
Les champs non statiques de la classe enfant (
Cat
) sont initialisés.
Cela se produit avant que leCat
constructeur ne commence à s'exécuter.
Lorsqu'il commence à s'exécuter, la variable tail a déjà une valeur :Le constructeur de la classe cat a démarré (le constructeur Animal est déjà terminé) Valeur actuelle de la variable statique catCount = 37 Valeur actuelle de tail = Valeur initiale de tail dans la classe Cat
-
Le constructeur de la
Cat
classe enfant s'appelleEt voilà à quoi ressemble la création d'un objet en Java !
Je dois dire que nous ne sommes pas de grands fans de l'apprentissage par cœur, mais il est préférable de mémoriser l'ordre d'initialisation des variables et des appels de constructeur .
Cela augmentera considérablement votre compréhension du déroulement du programme et de l'état de vos objets à un moment donné.
De plus, de nombreuses classes n'utilisent pas l'héritage. Dans ce cas, les étapes liées à la classe de base ne s'appliquent pas.
Plus de lecture : |
---|
GO TO FULL VERSION