POO Chap2
POO Chap2
POO Chap2
Reprenons notre exemple d'un livre défini par un titre et un auteur. Quand on y pense, un
CD musical n'a-t-il pas également un titre et un auteur ? Ce socle commun peut être mis
dans une classe média, en généralisant. Bien sûr, un livre possède des éléments
particuliers (nombre de pages, par exemple), et un CD également (durée).
Ce socle commun, c’est la classe mère. Les deux autres classes sont des classes filles. L'héritage
permet à ces classes filles de reprendre les mêmes attributs et méthodes que leur classe mère, et
d’ajouter en plus leur particularité en les spécialisant par des attributs et/ou méthodes qui leur sont
propres.
En d’autres termes, une classe mère sera considérée comme “notre référence” et grâce
au mécanisme d’héritage, on partagera ses attributs et méthodes à ses classes filles.
Dans l’exemple ci-dessous, nous avons une classe mère FigureGeometrique que
nous allons spécialiser en Carre . Le mot clé est extends. On peut dire que la
classe Carre étend la classe FigureGeometrique .
Commençons par définir la classe mère FigureGeometrique :
• #
Avec la classe Carre, nous récupérons automatiquement tous les attributs de la
classe de mère FigureGeometrique . Et nous lui avons ajouté un nouvel attribut de
classe et 2 nouvelles méthodes participant ainsi à la spécialisation.
Notons également que lorsqu’on fait de l’héritage, tous les champs sont hérités. Ils
peuvent être manipulés si leur accessibilité le permet (nous avons abordé ce concept
dans le chapitre 5 de la première partie).
• …
À quoi correspondent les objets de la classe dérivée ?
Tout objet d'une classe dérivée est considéré comme étant avant tout un objet de la
classe de base :
• tout objet d'une classe dérivée cumule les champs dérivés dans la classe de base
avec ceux définis dans sa propre classe :
class FigureGeometrique {
private int x;
private int y;
FigureGeometrique(int x, int y) {
this.x = x;
this.y = y;
}
}
Lorsque vous construisez une classe héritant d'une autre classe, vous avez la possibilité
de redéfinir certaines méthodes de la classe mère. Il s'agit de remplacer le comportement
de la fonction qui a été définie par la classe mère.
C’est le concept de polymorphisme. L’idée étant de pouvoir utiliser le même nom de
méthode sur des objets différents. Et bien sûr, cela n’a de sens que si le comportement
des méthodes est différent.
class Animal {
void deplacer() {
System.out.println("Je me déplace");
}
Sur toutes ces classes, vous pouvez donc appeler deplacer() . Le polymorphisme
permet alors d'appeler la méthode adéquate selon le type d'objet :
Même si le type de nos 3 variables sont les mêmes (Animal), les instances sont différentes
et donc leurs comportements aussi. Dans notre exemple, l'exécution donne comme
résultat :
Je me déplace
Je marche
Je vole surtout en ville
La redéfinition des méthodes dans la classe fille remplace tout le code de la méthode
mère. Parfois ce fonctionnement est idéal, parfois nous souhaitons quand même appeler
le code de la classe mère tout en ajoutant autre chose dans la classe fille.
Nous pouvons accéder à l’implémentation parente grâce au mot clé super, et appeler la
méthode déplacer avant d’ajouter l’aboiement du chien :
Attention, dans le cas d’un héritage multiple, il est seulement possible d'accéder à
l’implémentation de la classe parente, pas plus ! Dans notre exemple, si nous créons une
nouvelle classe fille Caniche qui étend de Chien, nous n’accéderons dans celle-ci avec
super qu’à l’implémentation de la classe Chien et non de la classe Animal.
Il existe en Java des types spéciaux commençant par@, appelés annotations. Ils
servent à préciser le comportement d’une classe, d’une méthode, d’un attribut ou même
d’une variable. Les annotations donnent des informations au compilateur pour
l'exécution du code de notre programme.
En Java, l'une des annotations les plus connues et utilisées est @Override. Elle est
utilisée en complément du polymorphisme pour indiquer que la méthode annotée est
une redéfinition d’une méthode de la classe mère. Si l’annotation est présente sur une
méthode, le compilateur va vérifier que la signature de la méthode est bien identique à
celle de la méthode dans la classe mère.
Reprenons une nouvelle fois notre exemple et voyons comment utiliser l'annotation
@Override :
class Animal {
void deplacer() {
System.out.println("Je me déplace");
}
class Chien extends Animal {
@Override
void deplacer() {
System.out.println("Je marche");
}
}
En résumé