Accueil > Programmation orientée objet >
En créant des logiciels plus complexes, plusieurs objets peuvent avoir des caractéristiques communes. Par exemple, un jeu vidéo peut avoir plusieurs types de personnages, mais tous les personnages ont des caractéristiques communes comme la position, la vitesse, la direction, etc. Dans ce cas, il est utile de créer une classe de base qui contient les caractéristiques communes, puis de créer des classes dérivées qui contiennent les caractéristiques spécifiques à chaque type de personnage.
L’héritage nous perment de déclarer une classe parente qui contient des attributs et des méthodes communes à plusieurs classes enfants.
Les classes enfants héritent des attributs et des méthodes de la classe parente. Les classes enfants peuvent supplanter la définition d’une méthode de la classe parente, comme on l’a déjà vu avec les méthodes toString(),
equals()et
hashCode()`. Elles peuvent aussi avoir leurs propres attributs et méthodes.
Seulement les attributs de visibilité protected
ou public
d’une classe parent seront hérités par les enfants. La nouvelle visibilité protected
est comme private
sauf pour les membres de la même famille. Donc, les attributs private
de la classe parent appartiennent uniquement au parent tandis que les attributs protected
seront hérités.
Notez que la visibilité par défaut (sans déclaration explicite) est
package-private
qui est commepublic
à l’intérieur du package et commeprivate
à l’extérieur. Vous ne pouvez pas explicitement déclarer quelque chosepackage-private
… simplement n’utilisez pas de mot-clé si vous voulez ce niveau de visibilité.
Une classe enfant indique son lien de parenté en utilisant le mot-clé extends
dans sa déclaration. Par exemple, la classe Warrior
peut être déclarée comme suit :
1
2
3
public class Warrior extends Player {
// ...
}
Une classe enfant peut réutiliser le constructeur de sa classe parente en utilisant la méthode super()
dans son constructeur. Par exemple, la classe Warrior
peut être déclarée comme suit :
1
2
3
4
5
public class Warrior extends Player {
public Warrior(String name, int health, int strength) {
super(name, health, strength);
}
}
présumant que la classe Player
a déclarée un constructeur comme suit :
1
2
3
4
5
6
7
8
9
10
11
public class Player {
protected String name;
protected int health;
protected int strength;
public Player(String name, int health, int strength) {
this.name = name;
this.health = health;
this.strength = strength;
}
}
Le mot-clé super() s’applique aux autres méthodes de la classe parente également. S’il est utilisé, ça doit toujours être la première instruction dans la méthode de la classe enfant qui supplante la méthode originale.
Dans un diagramme de classe UML, on indique la relation d’héritage avec une ligne solide et une tête de flèche en triangle pointant vers la classe parente. Par exemple, les classes Warrior
, Wizard
et Healer
héritent toutes de la classe Player
:
L’héritage est une relation “est un”. Par exemple, un Warrior
est un Player
. On peut donc utiliser un objet de type Warrior
partout où un objet de type Player
est attendu. Par exemple, on peut déclarer une variable de type Player
et lui assigner un objet de type Warrior
ou à d’autres types qui sont des extensions de Player
:
1
2
3
4
ArrayList<Player> players = new ArrayList<>();
players.add(new Warrior("Conan", 90, 10));
players.add(new Wizard("Gandalf", 50, 5));
players.add(new Healer("Rowena", 100, 2));
La liste est déclarée comme une liste de Player
, mais on peut y ajouter des objets de type Warrior
, Wizard
et Healer
parce que ces classes “sont des” Player
via l’héritage. Quand les objets de type parent pointent à des instances de type enfant, cela s’appelle le polymorphisme. Le polymorphisme fait spécifiquement référence à la capacité d’appeler la même méthode sur des objets de types différents et d’obtenir des résultats différents : cette méthode a plusieurs formes, littéralement la définition de polymorphisme.
La vidéo suivante présente un bon portrait du polymorphisme possible via l’héritage, soit celui qui est possible en prenant des types enfants pour le type parent : 📺 Upcasting et downcasting
À la fin de cette leçon vous devrez être en mesure de :
extends
et super
en Java.Quiz de validation des connaissances
Travail pratique :
Créer les fichiers appropriés pour les classes suivantes et remarquez ce qui se passe en lançant la classe App
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Parent {
String name;
Parent(String name) {
this.name = name;
}
void role() {
System.out.print("I'm the ");
}
void sayName() {
System.out.println("My name is " + name);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Dad extends Parent {
Dad(String name) {
super(name);
}
@Override
void role() {
super.role(); // toujours en premier... réutilise le code de la classe parente
System.out.println("dad.");
}
@Override // supplante (prend priorité sur) la version dans la classe parente
void sayName() {
System.out.println("My name is Mr. " + name + ".");
}
}
1
2
3
4
5
6
7
public class App {
public static void main(String[] args) {
Dad dad = new Dad("John");
dad.role();
dad.sayName();
}
}
Mom
et LegalGuardian
qui héritent de Parent
et qui modifient le code hérité de manière appropriée. Ajouter des déclarations dans la classe App
pour tester votre code.Parent
, Dad
, Mom
et LegalGuardian
et vérifier votre diagramme avec votre enseignant(e).