0% ont trouvé ce document utile (0 vote)
8 vues40 pages

Héritage et Polymorphisme en Java

Transféré par

Hicham Elhachami
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
8 vues40 pages

Héritage et Polymorphisme en Java

Transféré par

Hicham Elhachami
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Les fondements du langage Java

Chapitre 4
Héritage, Polymorphisme et Interfaces

Pr. Mohammed OUANAN

LST Informatique 2015-2016 M. OUANAN


Héritage

L'héritage est une notion fondamentale en Java et de manière générale dans les
langages de programmation par Objets. Il permet de créer de nouvelles classes par
combinaison de classes déjà existantes sans toucher au code source des classes
existantes.

Il permet de réutiliser une classe existante:

•En l'adaptant: ajouter de nouveaux attributs et méthodes à la nouvelle classe ou


adapter (personnaliser) les attributs et les méthodes de la classes existante.

•En la factorisant: plusieurs classes peuvent partager les mêmes attributs et les
mêmes méthodes.

-2-
Concept d’héritage de classes

♦ Toutes les classes dans Java dérive de la superclasse Object. Une sous-classe
hérite toutes les données et méthodes non privées de la superclasse. Les
méthodes et les données peuvent être référencées comme s’elles étaient
déclarées membres normales de la classe. La sous-classe n’hérite pas les
constructeurs de la superclasse. La sous-classe peut redéfinir les méthodes de
la superclasse.

♦ Avec l’héritage, les méthodes des classes existantes peuvent être réutilisés ou
changées. De nouveau champs et méthodes peuvent être ajoutés pour
s’adapter à de nouvelles situations.

-3-
Héritage multiple

♦ Dans les langages de POO comme C++, une classe peut dériver de plusieurs classes
parents ou superclasses. En Java, l’héritage multiple n’est pas permit. En effet,
JVM ne peut distinguer entre deux méthodes ayant le même nom mais
appartenant à des classes différentes pour savoir laquelle des deux il faut utiliser.
D’où, en Java, une classe ne peut dériver que d’une seule superclasse

-4-
Les mots clés de l’héritage en Java
♦ Le mot clé extends est utilisé pour signifier qu’une classe est une sous-classe de la class de
base

♦ super est le mot clé utilisé dans la sous-classe pour référencer les données et les méthodes
de la superclasse

♦ Une classe qui est déclarée abstract ne peut être utiliser pour l’instanciation d’objets

♦ Une classe peut implémenter plus qu’une interface. Le mot clé implements est utilisé avec
les interfaces

♦ Comme private, le modificateur d’accès protected restreint l’accès aux données membres et
aux méthodes. Mais contrairement au private, les sous-classes ont le droit d’accéder à
ces données membres et méthodes

-5-
Rôle des clés d’accès dans l’héritage
♦ La figure montre l’impact de l’héritage quand la sous-classe est dans le même ou différent
package que la classe de base. Rappelons que toutes les méthodes et les données de la
superclasse existent dans l’objet sous-classe, mis à part les attributs et les méthodes privés
qui restent inaccessible

-6-
Héritage

Syntaxe:
class <ClasseDerivee> extends <ClasseDeBase>
{
<implémentation du code>
}

Interprétation:
Permet de définir un lien d'héritage entre deux classes:

- La classe <ClasseDeBase> est le nom de la classe de base. On l’appelle aussi


une classe mère, une classe parente ou une superclasse.
Le mot clef extends indique la classe mère.

- La classe <ClasseDerivee> est le nom de la classe dérivée. Elle hérite de la


classe <ClasseDeBase> . On l'appelle aussi une classe fille ou une sous-classe.

-7-
Exemple d’héritage

-8-
Utilisation de this et de super
♦ Toutes les méthodes d’une sous-classe comprennent les variables this et super.
La variable this contient la référence à l’objet sous-classe. La variable super
contient la référence à l’objet de base

-9-
Redéfinition des méthodes

♦ L’habilité du programmeur à customiser la définition des méthodes de la superclasse


est connu sous le nom de redéfinition. C’est une autre composante de
l’héritage. N’importe quelle méthode héritée peut être redéfinit, sauf les
méthodes non privées qui ont été déclarées final dans la classe de base

♦ Critères de redéfinition des méthodes de la superclasse:


• La méthode de base ne peut être redéfinit qu’une fois dans la sous-classe
• Les listes d’arguments des méthodes qui ont été redéfinit doivent être de même type et
listés dans un ordre identique. Sinon elles sont considérées comme des méthodes
surchargées
• Le type de retour de la méthode de base doit être identique à celui de sa version redéfinit
dans la sous-classe
• L’accessibilité ne peut être plus restrictive que la méthode original

- 10 -
Exemple de méthodes redéfinies
♦ Supposons une superclasse Animal, ses sous-classes héritent de la méthode eat,
Ainsi, la méthode eat a été redéfinit dans chacune des sous-classes. La
méthode walk est utilisée par les deux objets Spider et cat, elle décrit combien
de genoux sont utilisés pour marcher. En revanche, comme l’objet fish ne
marche pas, cette méthode est redéfinit dans la class fish

- 11 -
Comparaison de la surcharge et de
la redéfinition des méthodes
Surcharge Redéfinition
Méthode doit être dans la même classe Méthode doit être dans la sous-classe
Méthode doit avoir le même nom mais Méthode doit avoir le même nom et les
des paramètres différents (l’ordre ou/et mêmes paramètres (en terme d’ordre et
le type des paramètres) de type de paramètres)
Le type de retour peut être différent (un Le type de retour doit être le même
type de retour différent seul n’est pas
suffisant pour les méthodes
surchargées, les paramètre doivent
aussi être différents)
Les signatures des méthodes sont Les signatures des méthodes sont
différentes identiques
Le modificateur d’accès de la méthode Le modificateur d’accès de la méthode
peut être plus privé que celui de la ne peut être plus privé que celui de la
méthode originale méthode originale
Les exceptions peuvent être différentes Les méthodes doivent envoyer des
(des exceptions différentes ne sont pas exceptions qui sont de même nature
assez pour les méthodes surchargées. que ceux de la méthode mère
Les paramètres doivent être différents)
Les méthodes peuvent éjecter plus Les méthodes ne peuvent envoyer plus
d’exceptions que la méthode original d’exceptions que la méthode de base
(un nombre différent d’exceptions seul qu’elles redéfinissent
n’est pas assez pour la surcharge des
méthodes, les paramètres doivent aussi
être différents)

- 12 -
L’héritage et les constructeurs

♦ Les constructeurs ne s’héritent pas comme les autres méthodes, même s’ils ne
sont pas privés. En effet, les constructeurs doivent être définis pour chacune
des sous-classes

♦ Une fois le modèle d’héritage est appliqué à la définition de la classe, si la classe


de base inclue un constructeur non null, la sous-classe doit aussi
explicitement comprendre le code pour les constructeurs et ne peut dépendre
du constructeur null pour sa création par le compilateur. Chaque constructeur
dans la sous-classe doit inclure un appel au constructeur de la superclasse

♦ Le mot clé extends implique qu’un objet de la superclasse est construit et ensuite
étendu pour inclure les données et les méthodes de la sous-classe

- 13 -
Critères d’héritage des constructeurs
Utilisation incorrecte de super Utilisation correcte de super et
et des constructeurs des constructeurs

♦ La superclasse Parent contient un constructeur explicite, le compilateur ne


fera donc pas appel au constructeur null et ne réussira pas la
compilation de la sous-classe (1). Pour corriger, le constructeur null de
la sous-classe Child doit être redéfinit pour faire appel au constructeur
de la superclasse (2)
- 14 -
Construction des classes dérivée

Lorsqu'on construit une instance de la classe dérivée, on obtient un objet :


- dont une partie est construite grâce à la définition de la classe dérivée
- et une partie grâce à la définition de la superclasse

En Java, le constructeur de la classe drivée doit prendre en charge l’intégralité de la


construction de l’objet.
► Le constructeur de la classe dérivée doit faire appel au constructeur de la classe
de base en appelant explicitement la méthode super() ainsi que la liste des
paramètres appropriés.

Remarque:
• les constructeurs ne sont pas hérités, mais on peut appeler ceux de la classe mère
avec super(…)
• l’appel du constructeur de la classe de base (appel de la méthode super()) doit être
la première instruction dans la définition du constructeur de la classe dérivée.

- 15 -
Exemple :
class ClasseDeBase{
public ClasseDeBase(int i) { // constructeur de la classe de base
[Link](" Classe de Base: " + i);
}
}
class ClasseDerivee1 extends ClasseDeBase {
public ClasseDerivee1(int i, int j) { // constructeur de la
classe dérivée 1
super(i+j); // appel du constructeur ClasseDeBase
[Link](" Classe dérivée1: " + i+ " , "+j);
}
}
class ClasseDerivee2 extends ClasseDerivee1{
public class TestHeritage{
public ClasseDerivee2(int i) { // constructeur de la classe dérivée 2 public static void main (String args[]) {
int j=i+300; ClasseDerivee2 objA=new ClasseDerivee2(7);
super(i,j); // appel du constructeur ClasseDerivee1 }
}
[Link](" Classe dérivée2: " + i);
} Sortie:
} Classe de Base : 314
Classe dérivée1: 7 , 307
Classe dérivée2: 7
- 16 -
Les cas possibles pour la constructions de classes dérivées
Exemple 1:
class ClasseDeBase{
public ClasseDeBase(arguments) { // Constructeur de la classe de base

}

}
class ClasseDerivee extends ClasseDeBase {
// Pas de constructeur
….
}

On obtient une erreur de compilation. Un constructeur de la classe dérivée doit


être défini et doit appeler le constructeur de la classe de base. Pourquoi ??

- 17 -
Exemple2:

class ClasseDeBase{
public ClasseDeBase(arguments1) { // constructeur de la classe de base

}
}
class ClasseDerivee extends ClasseDeBase {
public ClasseDerivee(arguments2) { // constructeur de la classe dérivée
/* Première instruction = Appel de super (arguments1)
C’est obligatoire sinon une erreur */
….
}
}

- 18 -
Exemple 3:

class ClasseDeBase{
public ClasseDeBase(arguments1) { // constructeur de la classe de base

}
public ClasseDeBase() { // constructeur sans paramètre de la classe de base

}
}
class ClasseDerivee extends ClasseDeBase {
public ClasseDerivee(arguments2) { // constructeur de la classe dérivée
// l’appel de super () n’est pas obligatoire.
/* si super() n’est pas explicitement appelé, alors le constructeur
sans paramètres de la classe de base est appelé par défaut. */
….
}
}

- 19 -
Exemple 4:

class ClasseDeBase{
// Pas de constructeur

}

class ClasseDerivee extends ClasseDeBase {


// Pas de constructeur
….
}

La création d’un objet de type ClasseDerivee entraîne l’appel de constructeur


par défaut qui appelle le constructeur par défaut de la ClasseDeBase.

- 20 -
Exemple pratique:

class ClasseDeBase{
public ClasseDeBase() {
[Link](" Classe de Base: ");
}
}
class ClasseDerivee1 extends ClasseDeBase {
public ClasseDerivee1() { public class TestHeritage{
// Appel implicite du constructeur sans paramètre de ClasseDeBase public static void main (String args[]) {
[Link](" Classe dérivée1: "); ClasseDerivee2 objA=new ClasseDerivee2();
} }
}
}
class ClasseDerivee2 extends ClasseDerivee1{ Sortie:
public ClasseDerivee2() { Classe de Base :
// Appel implicite du constructeur sans paramètres de ClasseDerivee1 Classe dérivée1:
[Link](" Classe dérivée2: " ); Classe dérivée2:
}
}

- 21 -
Un peu de théorie : Les règles

• Si la première instruction d’un constructeur n’est ni this(..) ni super(...)


alors java insère, comme première instruction, un appel implicite à
super()

• Si la première instruction d’un constructeur est super(...), alors java


appelle le constructeur (de la classe mére) choisi et exécute, au retour,
les instructions dun constructeur choisi.

• Si la première instruction est this, alors java invoque le constructeur (un


autre constructeur de la classe) sélectionné et l’appel au constructeur de
la classe mère est fait dans le constructeur surchargé (this).

• et ainsi de suite : La toute première instruction exécutée est donc le


constructeur de la classe Object

- 22 -
Exemple
class VehTerrestre {
VehTerrestre() { [Link](”Ter 0 arguments”) ; }
VehTerrestre(int n) { [Link](”Ter 1 arguments”) ; }
}

class Moto extends VehTerrestre {


Moto() {
super(2) ;
[Link](”Moto 0 arguments”) ;
}
Moto(String nom) {
[Link](”Moto 1 arguments”) ;
}
Moto(String nom,int n) {
this(nom) ;
[Link](”Moto 2 arguments”) ;
}
}

- 23 -
Le transtypage ?

Le transtypage d'un objet d'un type vers un autre type permet de modifier la façon
dont on "voit" l'objet mais ne le modifie pas. Pour transtyper un objet vers un
autre type, la notation est la même que pour le cast primitif:

(MaClasseDestination)monObjet

Il est possible de transtyper un objet vers un type ascendant ( le type de sa classe


mère ou la mère de sa mère etc...) même si ce transtypage est fait de façon
implicite. En effet, un objet Voiture par exemple est implicitement un Vehicule -
nul besoin de le transtyper en Vehicule pour accéder à ses propriétés et méthodes.

- 24 -
Héritage et transtypage: UpCasting

UpCasting:(caster vers une classe parente: classe fille vers classe mère)
Cette opération consiste à considérer une référence comme étant plus générale
que ce qu’elle est:

•Elle peut être fait de façon implicite.


• Les champs et les méthodes d’une classe sont en effet valides pour la
classe dérivée.
•il es utilisé pour profiter ensuite du polymorphisme.

Vehicule v = new Moto(”Fazer 600”) est un upcasting implicite

Vehicule v = (Vehicule) new Moto(”Fazer 600”) est un upcasting explicite


équivalent

Moto m= (Moto)v;//invalide, v n’est pas un Moto

- 25 -
Héritage et transtypage: DownCasting

DownCasting: (caster vers une classe enfant: classe mère vers classe fille)
Cette opération consiste à considérer une référence comme étant moins
générale que ce qu’elle semble être Nécessairement explicite

Intérêt: utilisé pour appeler une méthode de la classe fille qui n’existe pas dans
la classe mère

Vehicule d = new Avion(”Airbus A300”) ;

[Link]() ; /* Erreur */ ( decoller() est une méthode de la classe avion non


définie dans la classe Vehicule

((Avion)d).decoller() ; /* OK */

- 26 -
Classes Abstract
♦ Quand une classe dans l’hiérarchie sert comme plan de travail ou guide pour la
création des autres classes, la classe est alors définie comme abstract. Dans ce
cas, la classe ne peut être utilisée pour créer des objets ou stocker des données.
La classe est utilisée uniquement pour mettre en place les lignes de définitions
des autres sous-classes.

♦ Syntaxe d’une méthode abstract: abstract nom-méthode (arguments);


Des classes abstract peuvent contenir des méthodes abstract et des méthodes et données
concrètes. Une classe peut être déclarée abstract même s’elle ne contient aucune méthode
abstract

♦ Une méthode abstract ne comprend aucune ligne de code

♦ Une classe qui a une méthode abstract doit être déclarée comme abstract
abstract class NomClass { }
Les sous-classes qui dérivent de cette classe doivent implémenter du code pour cette méthode

- 27 -
Classe abstraite: But

Les classes abstraites sont utilisées pour

•Structurer l’ensemble des classes

•Faciliter la conception des classes en améliorant leur clarté

•Créer des modèles rigoureux pour créer des applications spécifique


Factoriser le code

•Permettre le polymorphisme

- 28 -
Exemple d’une classe Abstract

- 29 -
Classes Final
♦ Dans le modèle d’héritage, le mot clé final, quand appliqué aux méthodes de la
classe, empêche la méthode d’être redéfinit par n’importe quelle sous-classe

♦ Quand le mot clé final est appliqué à la définition de la classe, il empêche la classe
d’être utilisé comme superclasse. Cette classe ne peut donc être étendu.

♦ La classe String est un exemple de classe déclarée comme final, les classes
enveloppes des types primitives aussi. Si la classe doit être utilisé d’une manière
bien contrôlée, il faut la déclarer comme final

- 30 -
Le rationnel des interfaces
♦ Java fournie les classes interfaces pour implémenter l’héritage de deux sources
complètement indépendantes (Java n’autorise que l’héritage simple. Une classe
ne peut avoir qu’une seule superclasse. Une certaine forme d’héritage multiple
est obtenue grâce à la notion d’interface.)

♦ Les interfaces permettent au programmeur de définir des comportements dans les


sous-classes à partir de sources autres que leurs superclasses directe ou
indirectes

♦ La relation d’héritage “est un(e)” entre la superclasse et la sous-classe est valable


aussi pour les classes qui implémentent des interfaces

♦ Les interfaces sont des classes abstract qui définissent des constantes et méthodes
abstract. Elles servent comme outil de design des caractéristiques externes de
la classe. Toutes les méthodes dans une interface doivent être public

♦ Des classes disjoints peuvent implémenter la même interface. Une classe peut
implémenter autant d’interfaces qu'elle le souhaite

- 31 -
Exemple d’interface et héritage

- 32 -
Implémentation d’une interface
♦ L’implémentation d’une interface utilise le mot clé implements dans la
déclaration de la définition de la classe. Le compilateur s’assure que toutes
les méthodes déclarées dans l’interface sont aussi implémentées dans la
classe, même si on doit se ramener à une implémentation null d’une
méthode n’ayant aucune ligne de code

Implémentation null de
la méthode play (le
poisson ne chante pas)
- 33 -
Code d’implémentation d’interface

interface Pet
{
public void getName() ;
}

class Fish extends Animal implements Pet


{

public void getName()
{
// Code de la fonction getName
}

}

- 34 -
Interface et Transtypage

Il suffit de penser qu’une interface est une classe particulière (et


abstraite)
pour gérer le transtypage

Figure f = new Rectangle() ; /* Upcasting */


Rectangle r = (Rectangle)f ; /* Downcasting */

- 35 -
Contenu d’une interface

Une interface ne peut contenir que:


• Des méthodes abstract et public
• Des définitions des constantes publiques (public static final)
Les modificateurs public, abstract et final sont optionnels ( en ce cas, il
sont implicites)
Les interfaces ne peut contenir de méthodes static, final, synchronized
ou native,

- 36 -
Polymorphisme dans la création d’objet
♦ Polymorphisme veut dire “plusieurs formes”, il permet à un même code d’avoir
différents effets au moment de l’exécution et ceci en fonction du contexte. Le
polymorphisme prend avantage de l’héritage et de l’implémentation des
interfaces

♦ Il arrive qu'on veuille traiter un objet non en tant qu'objet du type spécifique
qu'il est, mais en tant qu'objet de son type de base. Cela permet d'écrire
du code indépendant des types spécifiques

♦ Par exemple, supposons qu’on veut créer une liste contenant des Prof,
Directeurs, Secrétaires, tous dérivant de Employe et dont chacune possède
sa propre méthode getDetails

Il suffit donc de créer un tableau de type Employe: Employe T[1...100]


On peut remplir ce tableau de Prof, Directeur, Secrétaire, etc. Ensuite pour
avoir les détails (par exemple) de la 5ième employée du tableau, il suffit
d’utiliser T[5].getDetails(…). On a pas besoin de savoir de quelle employée
il s'agit; on se contente de récupérer les détails via la spécification du type de
la classe de base
- 37 -
Exemple de Polymorphisme (1)

Employe
+ getDetails(return id, name); // définition de la classe
//
Employe e1 = new Employe();
Prof p1 = new Prof();
Prof Employe e2 = new Prof();
+getDetails(return id, name, class, grade);

L’appel de [Link] et [Link] traduisent différents comportements


et retournent différents résultats. L’objet référencé par e2 est un exemple de
polymorphisme. La variable e2 est de type Employe. L’objet crée et la
référence affectée à e2 est un objet Prof. Au moment de l’exécution,
[Link]() résultera dans l’invocation de la méthode getDetails de
l’objet Prof

- 38 -
Exemple de polymorphisme (2)
Une méthode qui reçoit
un type d’objet, peut être
appelée avec des objets
qui sont des sous-
Objet Employe comme argument classes de ce type, mais
pas avec des objets
superclasses de ce type

Ces instructions passent car


Prof est un Employe

Objet Prof comme argument

Objet Employe n’est pas


toujours un objet Prof

Cette instruction passe car


elle référence un objet Prof

- 39 -
Virtual method invocation (VMI)
Édition de lien dynamique (Dynamic
binding) détermine quelle méthode il
faut appeler au moment de l’exécution;
quand la méthode est implémenté par
plus d’une classe dans l’hiérarchie
d’héritage. JVM considérera le type de
l’objet effectivement crée et pas le type
avec lequel il a été déclaré:
Employe e2 = new Prof();
[Link]();

La technique de
résolution des arguments
passés à une méthode
est aussi connu sous le
nom de Dynamic
binding. JVM considère
uniquement le type
d’objet passé.

La technique de résolution
des comportements d’un
objet au moment de
l’exécution est connu sous le
nom de Virtual method
Invocation ou Dynamic
method binding

- 40 -

Vous aimerez peut-être aussi