1. Qu’est-ce que l’héritage ?
L’héritage est un mécanisme qui permet de créer une nouvelle classe à partir d’une classe existante, en « héritant » de ses propriétés et méthodes. La nouvelle classe s’appelle une sous-classe (ou classe dérivée), et l’original — la classe parente (ou classe de base).
C’est comme si vous faisiez un nouveau gâteau à partir d’une ancienne recette : vous prenez tout ce qu’il y a de mieux, vous ajoutez quelques ingrédients — et voilà, vous avez déjà « Le gâteau de grand-mère avec ingrédient secret ».
- La classe parente contient les propriétés et comportements communs.
- La sous-classe en hérite, et peut en plus ajouter quelque chose de propre ou modifier le comportement.
Par exemple, « Le chat est un animal » : tous les chats sont des animaux, mais tous les animaux ne sont pas des chats. Animal peut être une classe de base, et Cat — sa sous-classe. De même pour Dog, par exemple.
Ou encore « Le cercle est une figure » : chaque cercle est une figure, mais toute figure n’est pas un cercle. Figure peut être la classe parente, et Cercle et Triangle — ses héritiers. En Java, ces relations sont réalisées à l’aide du mot-clé extends.
Pourquoi a-t-on besoin de l’héritage ?
Question à un million : pourquoi ne pas simplement copier du code d’une classe à l’autre ? Pourquoi avoir inventé l’héritage ?
- Réutilisation du code : tout ce qui est commun est extrait dans une classe de base. Pas besoin de dupliquer les champs et les méthodes — ils apparaissent automatiquement dans les sous-classes. Par exemple, dans une application pour une université, la classe de base peut être « personne », qui a au minimum un nom et une date de naissance, et « étudiant » et « enseignant » — des sous-classes avec leurs propres propriétés.
- Extension et spécialisation : on peut ajouter de nouveaux champs et méthodes ou modifier les existants uniquement là où c’est nécessaire. Tous les animaux émettent des sons, mais le chat miaule et le chien aboie. On peut aussi donner au chat la capacité de grimper aux arbres (capacité absente de la classe de base).
- Structuration des hiérarchies : le code devient plus logique et lisible. Par exemple, si vous avez les classes Animal, Dog, Cat, on voit immédiatement que Dog et Cat sont des cas particuliers de Animal.
Exemple. S’il n’y avait pas d’héritage en Java, vous devriez copier des méthodes comme eat(), sleep() et le champ name dans chaque classe d’animal. Et si demain il faut ajouter une méthode breathe(), il faudra modifier des dizaines de classes ! Avec l’héritage, il suffit d’ajouter la capacité de respirer dans la classe de base.
2. Syntaxe de l’héritage : extends
Comment déclarer l’héritage en Java ? C’est très simple : utilisez le mot-clé extends.
class ParentClass {
// champs et méthodes
}
class Subclass extends ParentClass {
// champs et méthodes supplémentaires
}
Exemple 1 : Animaux
// Classe parente
class Animal {
String name;
void eat() {
System.out.println(name + " mange.");
}
}
// Sous-classe
class Cat extends Animal {
void meow() {
System.out.println(name + " dit: Miaou!");
}
}
Que se passe-t-il ici ?
- La classe Cat hérite de tous les champs et méthodes de la classe Animal.
- Donc Cat possède déjà le champ name et la méthode eat(), même si nous ne les avons pas écrits explicitement.
- En plus, Cat a sa propre méthode meow().
Utilisation
public class Main {
public static void main(String[] args) {
Cat kitty = new Cat();
kitty.name = "Buddy";
kitty.eat(); // Buddy mange. (hérité)
kitty.meow(); // Buddy dit: Miaou! (méthode propre)
}
}
Et voilà ! Nous avons obtenu une nouvelle classe avec un minimum de code, sans duplication.
3. Qu’est-ce qu’une sous-classe hérite exactement ?
En Java, une sous-classe hérite :
- De tous les champs et méthodes publics (public) et protégés (protected) de la classe de base.
- De tous les membres package-private si la sous-classe est dans le même package.
N’hérite pas :
- Des constructeurs (ils doivent être déclarés explicitement dans la sous-classe).
- Des champs et méthodes privés (private) (accessibles uniquement à l’intérieur de la classe de base elle-même).
- Des blocs d’initialisation statiques (ils ne sont pas hérités, mais chaque classe peut avoir les siens).
- Des membres avec un accès package-private, si la sous-classe se trouve dans un autre package.
Illustration
class Animal {
public String name;
private int age;
public void eat() {
System.out.println("Je mange");
}
private void secret() {
System.out.println("Secret!");
}
}
class Dog extends Animal {
public void bark() {
System.out.println("Ouaf!");
}
}
- Dog héritera du champ name et de la méthode eat().
- Dog ne voit pas le champ age ni la méthode secret() — ils sont privés.
4. Contraintes de l’héritage en Java
Java est plutôt stricte et a ses propres règles :
Un seul héritage de classes : chaque classe ne peut hériter que d’une seule autre classe. En revanche, une classe peut avoir autant de descendants que nécessaire.
class Dog extends Animal { ... } // OK
class Dog extends Animal, Pet { ... } // Erreur ! Impossible
Héritage multiple d’interfaces — possible, mais c’est une autre histoire dont nous parlerons plus tard.
La classe Object — l’ancêtre de toutes les classes en Java. Même si vous n’écrivez pas explicitement extends, votre classe hérite implicitement de Object.
5. Exemple pratique
Continuons à construire notre application « zoologique ».
Étape 1. Classe de base Animal
class Animal {
String name;
void eat() {
System.out.println(name + " mange.");
}
}
Étape 2. Sous-classe Cat
class Cat extends Animal {
void meow() {
System.out.println(name + " dit: Miaou!");
}
}
Étape 3. Sous-classe Dog
class Dog extends Animal {
void bark() {
System.out.println(name + " dit: Ouaf!");
}
}
Étape 4. Utiliser les classes
public class Main {
public static void main(String[] args) {
Cat cat = new Cat();
cat.name = "Bella";
cat.eat(); // Bella mange.
cat.meow(); // Bella dit: Miaou!
Dog dog = new Dog();
dog.name = "Charlie";
dog.eat(); // Charlie mange.
dog.bark(); // Charlie dit: Ouaf!
}
}
Qu’avons-nous obtenu ?
- Les deux classes Cat et Dog utilisent le champ commun name et la méthode eat() de la classe de base.
- Chaque classe ajoute son comportement unique : meow() pour le chat, bark() pour le chien.
- Si vous devez changer la façon dont les animaux mangent, il suffit de modifier la méthode eat() dans la classe Animal — les changements s’appliqueront automatiquement à tous les héritiers.
6. Points utiles
Visualisation : hiérarchie des classes
On peut représenter la hiérarchie ainsi :
. Animal
/ \
Cat Dog
- Animal — classe de base, contient tout ce qui est commun aux animaux.
- Cat et Dog — sous-classes, ajoutent des caractéristiques uniques.
Quelques mots sur les constructeurs et l’héritage
Les constructeurs ne sont pas hérités. Si vous ne définissez pas de constructeur dans la sous-classe, Java ajoutera automatiquement un constructeur sans paramètre (s’il existe chez le parent). Si la classe parente n’a qu’un constructeur avec paramètres, vous devez l’appeler explicitement dans la sous-classe via super(...). Petit exemple :
class Animal {
String name;
Animal(String name) {
this.name = name;
}
}
class Cat extends Animal {
Cat(String name) {
super(name); // on appelle le constructeur du parent
}
}
7. Erreurs courantes lors de l’utilisation de l’héritage
Erreur n° 1 : Tentative d’hériter de plusieurs classes à la fois.
En Java, on ne peut pas écrire class Cat extends Animal, Pet. Un seul parent !
Erreur n° 2 : S’attendre à ce que les champs et méthodes privés soient accessibles dans la sous-classe.
Les membres privés ne sont pas hérités (plus précisément, ils existent, mais ne sont pas accessibles depuis la sous-classe). Utilisez protected si vous devez autoriser l’accès aux héritiers.
Erreur n° 3 : Oublier d’appeler le constructeur du parent.
S’il n’y a pas de constructeur sans paramètre dans la classe de base et que vous n’appelez pas explicitement super(...), vous aurez une erreur de compilation.
Erreur n° 4 : Utiliser l’héritage « pour économiser du code » plutôt que par sens.
S’il n’y a pas de relation « est-un » (is-a) entre les classes, mieux vaut ne pas utiliser l’héritage. Par exemple, « Personne » ne doit pas hériter de « Voiture », même s’ils ont tous deux un champ speed.
GO TO FULL VERSION