L'héritage¶
La programmation orienté objet nous offre une façon de définir de nouvelles classes à partir de classe existante. C’est de l’héritage!
L’héritage est un concept fondamental de la programmation orienté objet. Ce concept permet la réutilisation de fonctionnalités (champs et méthodes) tout en apportant certaines variations spécifiques à l’objet héritant.
Effectivement l’héritage est un mécanisme qui permet, lors de la déclaration d’une nouvelle classe, d'y inclure les caractéristiques d’une autre classe.
On parle d'héritage, car le principe est en quelque sorte le même que celui d’un arbre généalogique; tout comme l'enfant hérite des caractéristiques du parent, une classe enfant hérite des caractéristiques de leur(s) classe(s) parent(s). L'héritage établit une relation de généralisation-spécialisation qui permet d'hériter dans la déclaration d’une nouvelle classe (classe enfant ou sous-classe) des caractéristiques (champs et méthodes) de la déclaration d'une autre classe (appelée classe parent ou super-classe).
En pratique pour déterminer si on doit utiliser l’héritage, une question s’impose... Est un? Est-ce qu’il existe une relation de type ‘est un’ entre la classe A et la classe B ?
En déclarant une nouvelle classe B par héritage de la classe A, et en y ajoutant nouvelles fonctionnalités, on peut dire que :
Aest une généralisation deBetBest une spécialisation deA;Aest une super-classe deBetBest une sous-classe deA;Aest la classe parent deBetBest une classe enfant deA.
Lorsqu'une classe enfant hérite d'une classe parent, elle peut alors utiliser les caractéristiques de la classe parent!
Pour utiliser l’héritage en Java, le mot clé extends nous permet de définir qui sera la classe parent.
Par exemple, prenons le cas suivant : nous avons les classes Personne, Étudiant et Enseignant.
Essayons de modéliser pour en faire ressortir la meilleure façon de procéder...
- Est-ce qu’un étudiant est une personne ?
- Est-ce qu’un enseignant est une personne ?
On pourrait penser, et avec raison, qu’un étudiant et un enseignant partagent certaines caractéristiques comme le nom ou le prénom.
Partons de cette réflexion afin de modéliser un diagramme représentatif en UML.
Ajoutons-y, des champs et des méthodes!
On peut constater que les classe Etudiant et Enseignant, utilisent tous les deux les mêmes propriétés, nom et prénom.
On pourrait dire que Etudiant et Enseignant hérite de la classe Personne!
Regardons maintenant comment traduite cela en code Java…Comme nous l’avons dit plus tôt le mot clé extends sera utiliser afin de définir la hiérarchie parent/enfant.
Un seul niveau d’héritage¶
Les mécanismes d’héritage de Java ne supportent qu’un seul niveau. Autrement dit, une classe enfant ne peut avoir qu’une seule classe parente.
L’héritage et la conversion de type (transtypage)¶
Il est possible de référencer une sous-classe (classe enfant) à partir d’une instance de la super classe (classe parent).
Par exemple en utilisant l’example précédant, il est possible d’utiliser une instance de type Etudiant comme une instance de type Personne.
En effet, parce que la classe Etudiant hérite de la classe Personne, on peut aussi dire qu'un Etudiant est aussi une Personne.
Voici un exemple Java :
Etudiant etudiant = new Etudiant("nom", "prenom", 123456);
Personne personne = etudiant;
System.out.println(personne.getNom());
// Pouvons nous faire ceci ?
System.out.println(personne.getNoDA());
Premièrement, une instance de Etudiant est créée.
Deuxièmement, l’instance Etudiant est assigné à une variable de type Personne.
Maintenant, la variable de type Personne (référence) pointe vers une instance de type Etudiant.
Cela est rendu possible par le fait que la classe Etudiant hérite de la classe Personne.
Le processus de référencement à une classe en utilisant un type différent de la classe elle-même est appeler transtypage (type casting, casting).
On peut transtyper des objets d’un type à un autre!
Transtypage vers le haut et vers le bas (Upcasting, Downcasting)¶
On peut forcer la conversion de type (transtypage) d’une sous-classe vers une super-classe.
On appelle ça le transtypage vers le haut (upcasting).
Il peut aussi être possible de forcer la conversion de type d’une super-classe vers une sous-classe, mais si et seulement si, cet objet est réellement une instance de la sous-classe.
Voici un exemple valide de transtypage vers le bas :
Etudiant etudiant = new Etudiant("nom", "prenom", "123456");
//Upcast vers Personne
Personne personne = etudiant;
//Downcast vers Etudiant
Etudiant etudiant2 = (Etudiant) personne;
&mnsp;
Redéfinition de méthodes¶
Dans une sous-classe, il est possible de redéfinir (override) les méthodes définies d'une super-classe.
Changer l,example pour point/tringle cercle et calculer l,aider
Regardez bien comme les deux (2) classes Personne et Enseignant définissent une méthode setNom().
A partir de ce moment quand la méthode setNom() est appelé sur un objet de type Enseignant, c’est celle dans la classe Enseignant qui sera appelé, la méthode dans la super-classe sera ignoré.
Pour redéfinir une méthode, la signature de la méthode dans la classe enfant doit être la même que celle de la classe parent. Autrement dit, la définition de la méthode dans la sous-classe doit avoir exactement le même nom et le même nombre et type de paramètre en plus d’être lister dans la bonne séquence.
Il est impossible en Java de redéfinir des méthodes privées d’une super-classe.
Finalement l’écosystème Java met à notre disposition l’annotation @Override.
Celle-ci permet au compilateur Java de savoir quelles méthodes doivent être redéfinies mais aussi de savoir que si la signature change ou la méthode est renommée, la méthode est toujours belle est bien redéfinie.
Méthodes de super-classe¶
Si une méthode est redéfinie dans une sous-classe mais, que nous avons besoin d’accéder à la méthode dans la super classe, que faire?
Au même titre que le mot clé this permet d’accéder aux propriétés de la classe courante, le mot clé super nous permet d’accéder aux propriétés de la classe mère!
Dans cet exemple, la méthode setNom() dans la classe Enseignant appelle la méthode setNom() de la classe Personne.
Il est possible d’appeler n’importe quelle méthode dans une sous-classe, il n’est pas obligatoire de la faire dans une méthode redéfinie.
Le mot clé instanceof¶
Le langage Java possède un mot clé instanceof qui permet de déterminer si un objet donné est une instance d’une classe en particulier.
En voici un exemple :
Enseignant enseignant = new Enseignant();
Triangle triangle = new Triangle();
if(enseignant instanceof Enseignant){
System.out.println("enseignant est une instance de la classe Enseignant");
}
if(enseignant instanceof Personne){
System.out.println("enseignant est une instance de la classe Personne");
}
if(triangle instanceof Personne){
System.out.println("triangle est une instance de la classe Personne");
}
L’instruction instanceof peut aussi être utilisé pour déterminer si le type est une instance d’une super classe de sa classe.
Comme on peut le constater, instanceof nous permet d’explorer la hiérarchie de l’héritage.
L’héritage et les champs¶
En Java, les champs (données) ne peuvent pas être redéfini dans une classe enfant.
Si on définit un champ dans une sous classe avec le même nom que celui de la super classe, les champs de la sous classe auront préséance sur ceux de la super classe.
L’héritage et les constructeurs¶
Le mécanisme d’héritage de Java n’inclut pas les constructeurs.
En d’autres mots, les constructeurs d’une super classe ne sont pas hérités d’une sous classe.
Les sous-classes peuvent quand même accéder aux constructeurs de leur super classe en utilisant le mot clé super.
En fait, un constructeur d’une sous classe devrait appeler le constructeur de sa super classe en premier lieux.
Voyons à quoi cela pourrait ressembler :
public class Personne {
public Personne() {
}
}
public class Enseignant extends Personne{
public Enseignant() {
super();
}
}
Vous remarquerez l’appel à super à l’intérieur du constructeur de la classe Enseignant.
L’appel à super exécutera l’appel au constructeur de la classe Personne.
Vous avez peut-être déjà vu des classes Java ou les constructeurs de la sous classe ne semblait pas appeler le constructeur de la super classe ? Peut-être même que la super classe n’avait même pas de constructeur ? Voyons pourquoi…
Si une classe n’as pas de constructeur explicitement défini, le compilateur Java insérera automatiquement un constructeur par défaut sans argument.
De ce fait, une classe possède toujours un constructeur vide par défaut.
Alors, nous pourrions dire que la proposition suivante est équivalente à la précédente.
De plus, si un constructeur n’appel pas de manière implicite un constructeur dans la super classe, le compilateur Java insèrera automatiquement un appel au constructeur vide de la super classe.Ce qui veut dire que la version de la classe Enseignant suivante est équivalente à la précédente.
En fait, comme le constructeur est maintenant vide, il pourrait être omis et le compilateur Java l’insérerait automatiquement et plus d’inséré un appel au constructeur vide de la super classe. Ce qui donnerait un code ressemblant à :
Même si aucun constructeur n’est déclaré dans ces deux classes, les deux (2) obtiennent un constructeur vide par défaut et le constructeur vide de la classe Enseignant appellera le constructeur vide de la classe Personne.
Par contre, si la classe Personne n’avais pas de constructeur vide, mais avait un autre constructeur avec des paramètres, le compilateur Java ne l’accepterais pas!
Les classes constantes et l’héritage¶
Une classe peut être déclarée final, cependant une classe constante ne peut pas être étendu (hérité de).
En bref, on ne peut pas utiliser l’héritage avec une classe constante.