|
1 | 1 | # Héritage |
2 | 2 |
|
3 | | -L’héritage est un des piliers de la programmation orientée objet. Il permet de créer de nouvelles classes à partir de classes existantes, en réutilisant et en spécialisant leur comportement. Cela favorise la factorisation du code et la création de hiérarchies logiques. |
| 3 | +L’héritage est l’un des concepts fondamentaux de la programmation orientée objet (POO), au même titre que l’encapsulation et le polymorphisme. Il permet de créer de nouvelles classes à partir de classes existantes, en réutilisant et en spécialisant leur comportement. Grâce à l’héritage, on peut factoriser le code commun à plusieurs classes et organiser les concepts de manière hiérarchique, ce qui favorise la lisibilité, la maintenance et l’évolution des programmes. |
4 | 4 |
|
5 | | -> **À retenir** : Grâce à l’héritage, une classe « enfant » hérite des attributs et méthodes de sa classe « parent », et peut en ajouter ou en modifier. |
| 5 | +> **Définition** : L’héritage consiste à définir une nouvelle classe (dite « classe dérivée » ou « classe enfant ») à partir d’une classe existante (dite « classe de base » ou « classe parente »). La classe enfant hérite des attributs et des méthodes de la classe parente, et peut en ajouter ou en modifier. |
| 6 | +
|
| 7 | +## Pourquoi utiliser l’héritage ? |
| 8 | + |
| 9 | +- **Réutilisation du code** : Éviter de réécrire plusieurs fois le même code dans différentes classes. |
| 10 | +- **Organisation logique** : Structurer les concepts selon des relations « est-un » (ex : un Chien est un Animal). |
| 11 | +- **Extensibilité** : Ajouter facilement de nouveaux comportements spécifiques sans toucher au code existant. |
| 12 | + |
| 13 | +> **Exemple d’analogie** : Dans la vie courante, on peut dire qu’un vélo, une voiture et un camion sont tous des véhicules. Ils partagent des caractéristiques communes (roues, moteur, capacité à se déplacer), mais chacun a aussi ses particularités. En POO, on modélisera cela par une classe `Vehicule` dont hériteront les classes `Velo`, `Voiture`, `Camion`. |
| 14 | +
|
| 15 | +--- |
6 | 16 |
|
7 | 17 | ## Mot-clef `extends` |
8 | 18 |
|
9 | | -Pour hériter d’une classe en Java, on utilise le mot-clé `extends`. |
| 19 | +Pour hériter d’une classe en Java, on utilise le mot-clé `extends`. Cela signifie littéralement « étendre » la classe de base, c’est-à-dire en reprendre les caractéristiques tout en les complétant ou en les spécialisant. |
10 | 20 |
|
11 | 21 | ```java |
12 | 22 | class Personne { |
@@ -34,11 +44,15 @@ class Enfant extends Personne { |
34 | 44 | } |
35 | 45 | ``` |
36 | 46 |
|
37 | | -> **Info** : Le mot-clé `super` permet d’appeler le constructeur ou les méthodes de la classe parente. |
| 47 | +Dans cet exemple, les classes `Adulte` et `Enfant` héritent de la classe `Personne`. Elles récupèrent automatiquement les attributs `nom` et `prenom`, ainsi que les méthodes publiques de `Personne`. Elles peuvent aussi ajouter leurs propres attributs ou redéfinir des méthodes si besoin. |
| 48 | + |
| 49 | +> **Info** : Le mot-clé `super` permet d’appeler le constructeur ou les méthodes de la classe parente. C’est utile pour initialiser les attributs hérités ou réutiliser du code parent. |
| 50 | +
|
| 51 | +--- |
38 | 52 |
|
39 | 53 | ## Polymorphisme de méthodes |
40 | 54 |
|
41 | | -Le polymorphisme permet d’utiliser un objet enfant comme s’il était de type parent. Cela autorise l’utilisation de méthodes de la classe parente, mais ces méthodes peuvent être redéfinies (surchargées) dans la classe enfant. |
| 55 | +Le polymorphisme est la capacité d’un même nom de méthode à se comporter différemment selon l’objet qui la porte. Grâce à l’héritage, on peut utiliser un objet enfant comme s’il était de type parent. Cela autorise l’utilisation de méthodes de la classe parente, mais ces méthodes peuvent être redéfinies (on parle alors de « surcharge » ou plutôt de « redéfinition », en anglais *override*) dans la classe enfant. |
42 | 56 |
|
43 | 57 | ```java |
44 | 58 | class Point { |
@@ -95,36 +109,49 @@ public class Program { |
95 | 109 | } |
96 | 110 | ``` |
97 | 111 |
|
98 | | -> **À savoir** : Le mot-clé `@Override` indique que la méthode redéfinit une méthode de la classe parente. Cela permet d’éviter les erreurs de signature. |
| 112 | +Dans ce code, la méthode `getNom()` est redéfinie dans chaque sous-classe. Lorsqu’on appelle `getHelloStr()` sur une variable de type `Forme`, c’est la version la plus spécialisée de `getNom()` qui est utilisée, selon le type réel de l’objet (ici, `Cercle` ou `Rectangle`). |
| 113 | + |
| 114 | +> **À savoir** : Le mot-clé `@Override` indique que la méthode redéfinit une méthode de la classe parente. Cela permet d’éviter les erreurs de signature et améliore la lisibilité du code. |
| 115 | +
|
| 116 | +--- |
99 | 117 |
|
100 | 118 | ## Classes abstraites |
101 | 119 |
|
102 | | -Une classe abstraite est une classe que l’on ne peut pas instancier directement. Elle sert de modèle pour d’autres classes, qui devront en hériter et compléter les méthodes abstraites. |
| 120 | +Une classe abstraite est une classe que l’on ne peut pas instancier directement. Elle sert de modèle pour d’autres classes, qui devront en hériter et compléter les méthodes abstraites. C’est un outil puissant pour imposer une structure commune à plusieurs classes, tout en laissant la liberté de spécialiser certains comportements. |
| 121 | + |
| 122 | +- Une classe abstraite peut contenir des attributs, des méthodes concrètes (avec code) et des méthodes abstraites (sans code, juste la signature). |
| 123 | +- On est donc obligé de créer une sous-classe qui en dérive et qui implémente les méthodes abstraites : |
103 | 124 |
|
104 | | -- Une classe abstraite peut contenir des attributs, des méthodes concrètes (avec code) et des méthodes abstraites (sans code). |
105 | | -- On est donc obligé de créer une sous-classe qui en dérive : |
| 125 | +> **À noter** : Même si une classe abstraite ne peut pas être instanciée directement, elle peut parfaitement définir un ou plusieurs constructeurs. Ceux-ci servent à initialiser les attributs hérités par les sous-classes. Lorsqu’une sous-classe hérite d’une classe abstraite, elle peut (et doit souvent) appeler le constructeur de la classe abstraite via `super(...)` dans son propre constructeur. Cela permet de garantir que l’état de l’objet est correctement initialisé, même si l’on ne crée jamais d’instance directe de la classe abstraite. |
106 | 126 |
|
107 | 127 | ```java |
108 | 128 | abstract class Forme { |
109 | 129 | protected Point centre; |
110 | 130 | public Forme(Point c) { |
111 | 131 | this.centre = c; |
112 | 132 | } |
| 133 | + public abstract double getAire(); // Méthode abstraite |
113 | 134 | } |
114 | 135 | class Cercle extends Forme { |
115 | 136 | protected double rayon; |
116 | 137 | public Cercle(Point c, double rayon) { |
117 | | - super(c); |
| 138 | + super(c); // Appel du constructeur de la classe abstraite |
118 | 139 | this.rayon = rayon; |
119 | 140 | } |
| 141 | + @Override |
| 142 | + public double getAire() { |
| 143 | + return Math.PI * rayon * rayon; |
| 144 | + } |
120 | 145 | } |
121 | 146 | // Dans le main : |
122 | 147 | Cercle c = new Cercle(new Point(5, 6), 5.2); // OK |
123 | 148 | Forme fc = new Cercle(new Point(5, 7), 3.0); // OK |
124 | 149 | // Forme f = new Forme(new Point(0,0)); // Erreur : on ne peut pas instancier une classe abstraite |
125 | 150 | ``` |
126 | 151 |
|
127 | | -> **Info** : Utilisez les classes abstraites pour définir des comportements communs à plusieurs classes, tout en forçant la spécialisation de certaines méthodes dans les sous-classes. |
| 152 | +> **Info** : Utilisez les classes abstraites pour définir des comportements communs à plusieurs classes, tout en forçant la spécialisation de certaines méthodes dans les sous-classes. Cela permet de garantir que toutes les sous-classes respecteront un contrat minimal. |
| 153 | +
|
| 154 | +--- |
128 | 155 |
|
129 | 156 | ## Le mot-clé `super` et la résolution statique |
130 | 157 |
|
@@ -156,9 +183,9 @@ public class Demo { |
156 | 183 | } |
157 | 184 | ``` |
158 | 185 |
|
| 186 | +> **Astuce :** Utilisez `super` pour accéder à une méthode ou un constructeur parent, mais gardez en tête que le polymorphisme ne s'applique pas à `super`. |
159 | 187 |
|
160 | | -> **Astuce :** |
161 | | -> Utilisez `super` pour accéder à une méthode ou un constructeur parent, mais gardez en tête que le polymorphisme ne s'applique pas à `super`. |
| 188 | +--- |
162 | 189 |
|
163 | 190 | ## Détail de l'exemple sur `super` et `this` |
164 | 191 |
|
@@ -205,14 +232,20 @@ Cet exemple est fondamental pour bien comprendre le comportement de l'héritage |
205 | 232 |
|
206 | 233 | --- |
207 | 234 |
|
208 | | -L’héritage et le polymorphisme sont essentiels pour structurer des programmes évolutifs et réutilisables. N’hésitez pas à expérimenter avec vos propres hiérarchies de classes pour bien comprendre leur puissance et leurs subtilités ! |
209 | | - |
210 | | ---- |
211 | | - |
212 | 235 | ## Encadré : SOLID et héritage |
213 | 236 |
|
214 | 237 | L’héritage est directement concerné par le principe de substitution de Liskov (**L** de SOLID) : toute classe dérivée doit pouvoir être utilisée à la place de sa classe parente sans altérer le bon fonctionnement du programme. |
215 | 238 |
|
216 | 239 | > **À retenir :** Respecter ce principe garantit la robustesse et la cohérence de vos hiérarchies de classes. |
217 | 240 |
|
218 | 241 | Pour une explication complète des principes SOLID, voir le chapitre dédié. |
| 242 | + |
| 243 | +--- |
| 244 | + |
| 245 | +## Pour aller plus loin |
| 246 | + |
| 247 | +- **Composition vs héritage** : L’héritage n’est pas la seule façon de réutiliser du code. Parfois, il est préférable d’utiliser la composition (une classe possède une autre classe) plutôt que l’héritage (une classe est une autre classe). On parle alors du principe « favor composition over inheritance ». |
| 248 | +- **Limites de l’héritage** : Un mauvais usage de l’héritage peut conduire à des hiérarchies trop rigides ou à des problèmes de maintenance. Il est important de bien réfléchir à la structure de ses classes. |
| 249 | +- **Interfaces** : En Java, une classe peut hériter d’une seule classe (héritage simple), mais peut implémenter plusieurs interfaces. Les interfaces permettent de définir des contrats que les classes doivent respecter, sans imposer d’implémentation. |
| 250 | + |
| 251 | +N’hésitez pas à expérimenter avec vos propres hiérarchies de classes pour bien comprendre la puissance et les subtilités de l’héritage en Java ! |
0 commit comments