Title: ENSTA IN204 Introduction JAVA
1ENSTA IN204Introduction à JAVA
LIP6 cours L3 POBJ Programmation par Objets
(en Java)
- Olivier Sigaud
- LIP6/AnimatLab
- olivier.sigaud_at_lip6.fr
- 01.44.27.88.53
2Plan du cours 5
- Le polymorphisme
- Labstraction
- L'héritage multiple
- Les interfaces
- Les problèmes du polymorphisme
inséparables
inséparables
3Polymorphisme(rappel)
4Héritage et traitements
- L'héritage permet d'organiser les données sous
forme de classes de façon à coller à la
sémantique du domaine modélisé - Mais l'héritage permet aussi d'organiser les
traitements de façon à éviter les répétitions de
code - Pour utiliser correctement lhéritage, il faut du
polymorphisme et de l'abstraction
5Polymorphisme exemple (1)
- class Vehicule
- void demarrer()
-
-
- class Garagiste
- public static void garer(Vehicule v)
- v.demarrer()
-
- class Main
- public static void main(String args)
- Voiture voiture new Voiture()
- Garagiste.garer(voiture)
-
- Bien que, syntaxiquement, v soit un véhicule,
l'objet est une voiture
class Voiture extends Vehicule void
demarrer()
Méthode appelée ici
6Polymorphisme exemple (2)
- class Vehicule
-
- class Garagiste
- public static void garer(Vehicule v)
- v.demarrer()
-
- class Main
- public static void main(String args)
- Voiture voiture new Voiture()
- Garagiste.garer(voiture)
-
- Javac vérifie syntaxiquement que la classe
mentionnée possède bien la méthode
class Voiture extends Vehicule void demarrer()
Ne compile pas !!!
7Polymorphisme implicite synthèse
- Java connaît la classe de l'objet même si ce
n'est pas le type spécifié dans le code source - Si l'objet passé en paramètre (Vehicule v) est
une Voiture, il appellera la méthode demarrer()
de la classe Voiture - Il suffit que Voiture hérite de Vehicule
- Si la méthode appelée existe pour les deux types,
alors Java appellera celle de la classe de
l'objet, même si le type mentionné est différent - Si la méthode appelée n'existe pas pour le type
spécifié, alors Java refuse de compiler
8Polymorphisme implicite problème
- Pour que le code précédent compile, il faut que
la classe Vehicule dispose d'une méthode
demarrer(). - Mais il se peut que l'on ne soit pas capable
d'écrire le code d'une méthode démarrer pour une
classe Vehicule représentant un véhicule
quelconque. - Deux solutions
- Le polymorphisme explicite
- Les méthodes (et classes) abstraites
9Polymorphisme explicite
- Si lon veut appeler une méthode qui n'existe que
pour le type spécifique, alors il faut caster
, c'est-à-dire déclarer un type plus spécifique
pour l'objet - Le cast est utile à la compilation il
permet dindiquer au compilateur que lobjet est
dun type plus spécifique et donc de vérifier que
la méthode spécifique qui sera appelée existe
bien - Si l'on caste alors que la classe de l'objet
n'est pas compatible avec le type casté, Java
lève à l'exécution l'exception
ClassCastException
10Polymorphisme explicite exemple (1)
- class Vehicule
-
- class Garagiste
- public static void garer(Vehicule v)
- ((Voiture)v).demarrer()
-
- class Main
- public static void main(String args)
- Voiture voiture new Voiture()
- Garagiste.garer(voiture)
-
- Problème la méthode garer(Vehicule v) n'est
plus générique, elle ne marche que pour les
voitures
class Voiture extends Vehicule void
demarrer()
Java sait que l'objet sera une voiture
11Polymorphisme explicite exemple (2)
- class Vehicule
-
- class Garagiste
- public static void garer(Vehicule v)
- ((Voiture)v).demarrer()
-
- class Main
- public static void main(String args)
- Camion cam new Camion()
- Garagiste.garer(cam)
-
- Solution éventuelle vérifier le type de l'objet
class Voiture extends Vehicule void
demarrer()
ClassCastException à l'exécution
12Polymorphisme explicite exemple (3)
- class Vehicule
-
- class Garagiste
- public static void garer(Vehicule v)
- if (v instanceof Voiture)
- ((Voiture)v).demarrer()
- else if (v instanceof Camion)
- ((Camion)v).demarrer() //
-
-
- Problème il faut connaître la liste des types
possibles
class Voiture extends Vehicule void
demarrer()
13Connaître le type d'un objet
- if (v instanceof Vehicule) vérifie si v est un
pointeur sur un objet de type Vehicule ou bien
tout type plus spécifique que Vehicule - Si v est un Camion, renvoie true
- if (v.getClass().getName().equals("Vehicule"))
vérifie si v est un pointeur sur un objet de type
Vehicule. - Si v est un Camion, renvoie false
- Cette deuxième méthode fait appel à la
réflexivité (quel est le nom de la classe de
l'objet ?) - Problème la vérification explicite du type de
lobjet est ce que lon cherche à éviter en POO
14L'abstraction
15Autre solution abstraction
class Voiture extends Vehicule void
demarrer()
- class Vehicule
- abstract void demarrer()
-
- class Garagiste
- public static void garer(Vehicule v)
- v.demarrer()
-
- class Main
- public static void main(String args)
- Voiture voiture new Voiture()
- Garagiste.garer(voiture)
-
- La classe Vehicule possède une méthode
demarrer(), donc la compilation fonctionne.
A l'exécution, Java sait que l'objet est une
voiture
16Méthode abstraite
- Il peut être impossible de spécifier un
comportement d'une classe générique - ex Forme calculerSurface()
- Mais on peut avoir besoin de ce comportement au
niveau générique - ex Forme trierParSurfacesCroissantes()
- Dans ce cas, on déclare la méthode abstraite
- public abstract void maMethode()
- Toutes les classes qui en héritent doivent la
spécifier, faute de quoi elles sont abstraites
17Abstraction contraintes
- Pour que lexemple précédent marche
- On ne connaît pas le comportement demarrer()
pour les objets de type Vehicule - Il ne faut pas pouvoir créer un objet du type
Vehicule - Il faut que tout objet dun type qui hérite de
Vehicule dispose dun comportement demarrer()
concret - Donc toutes les méthodes abstraites doivent être
redéfinies dans les classes filles - Les classes qui dérivent d'une classe abstraite
doivent instancier toutes ses méthodes abstraites
(sinon, elles sont abstraites à leur tour)
18Classe abstraite
- Une classe qui a une méthode abstraite est
nécessairement abstraite - Lorsquune classe est abstraite, aucun objet du
programme ne peut être instance de cette classe - Donc ne peut pas construire une instance d'une
classe abstraite - Cependant, une classe abstraite a généralement
des constructeurs - Ces constructeurs sont appelés lors de la
construction des sous-classes (avec super())
19Abstraction conséquence
class Voiture extends Vehicule void
ouvrirPorte()
- class Vehicule
- abstract void ouvrirPorte()
-
- class Garagiste
- public static void garer(Vehicule v)
- v.ouvrirPorte() v.demarrer()
-
- class Main
- public static void main(String args)
- Velo v new Velo()
- Garagiste.garer(voiture)
-
- On est contraint dajouter une méthode
ouvrirPorte() dans la classe Velo, mais on ne
sait pas la spécifier
class Velo extends Vehicule void ouvrirPorte()
???
20Mélange explicite / implicite exemple
- class Garagiste
-
- public void garer(Vehicule v)
-
- if (!(v instanceof Velo))
-
- v.ouvrirPorte()
- v.demarrer()
-
- else ((Velo)v).pedaler()
-
-
-
- La classe Velo ne possède pas de méthode
ouvrirPorte() - Seule la classe Velo possède une méthode
pedaler() - Dans un tel cas, pour que cela compile, il faut
caster
21Polymorphisme et abstraction synthèse
- Pour définir un traitement abstrait, il faut
choisir - Doter la classe abstraite d'une méthode abstraite
et utiliser le polymorphisme implicite - Faire l'économie d'une méthode abstraite et
caster - La première solution est souvent bien meilleure !
- Mais cela suppose que toutes les classes
concrètes disposent du traitement déclaré au
niveau générique
22Héritage multiple et interfaces
23Imaginons un traitement générique
- class Marchand extends Vector
-
- public BienDeConso getProduit(int index)
- return (BienDeConso)get(index)
-
- public void vendre()
-
- for (int i0iltsize()i)
-
- BienDeConso bien getProduit(i)
- bien.vendre()
-
-
24Puis un deuxième
- class Garagiste extends Vector
-
- public Vehicule getVehicule(int index)
- return (Vehicule)get(index)
-
- public void garer()
-
- for (int i0iltsize()i)
-
- Vehicule v getVehicule(i)
- v.garer()
-
-
25L'héritage multiple
- Une voiture est un véhicule et un bien de
consommation (on peut la vendre et la conduire) - On aimerait pouvoir appliquer les traitements
génériques précédents à une même instance de la
classe Voiture. - On aimerait bien (mais on ne peut pas) écrire
- class Voiture extends Vehicule, BienDeConso
26L'héritage multiple le problème
class BienDeConso void afficher()
class Vehicule void afficher()
?
Voiture v new Voiture() v.afficher()
- Problème si une classe hérite de 2 classes et
si ces 2 classes ont 2 méthodes de même signature
(ou 2 attributs de même nom), de laquelle
(duquel) hérite la première ? - Permis en C, OCAML
- Interdit en Java
27L'héritage multiple le choix de JAVA
- Problèmes dans les cas où
- on pourrait déclencher deux traitements hérités
différents à partir d'un même appel, en ne
sachant pas lequel choisir - on pourrait avoir deux valeurs différentes pour
le même attribut hérité, en ne sachant pas lequel
choisir - Pas de problème avec une méthode abstraite elle
sera redéfinie au niveau de la classe fille - Donc on peut faire de l'héritage multiple avec
des classes purement abstraites (que des méthodes
abstraites) et sans attributs
28Les interfaces
- Formellement équivalentes à une classe totalement
abstraite - pas d'attributs (sauf éventuellement static)
- que des méthodes abstraites
- Exemple
- interface Drawable
-
- public void draw()
- public void refresh()
- public void erase()
-
- Interfaces utiles (à connaître) Cloneable,
Serializable
29Interfaces pour quoi faire ?
- Une classe qui implémente une interface doit
implémenter toutes ses méthodes - contrat à respecter
- Une classe peut implémenter plusieurs interfaces
- Le polymorphisme fonctionne sur les interfaces
- L'héritage entre interfaces fonctionne
- Fournit un équivalent de l'héritage multiple
- Mais on ne peut pas hériter du code
30Héritage mulitple solution
interface BienDeConso void afficher() void
vendre() void acheter()
interface Vehicule void afficher() void
demarrer() void conduire()
- class Voiture implements Vehicule, BienDeConso
-
- public void afficher() // ici, le traitement
d'affichage - public void vendre() // ici, le traitement de
vente - public void acheter() // ici, le traitement
d'achat - public void demarrer() // ici, le traitement
de demarrage - public void conduire() // ici, le traitement
de conduite
31Interfaces que faire ?
- Quand une classe ne contient que des méthodes
abstraites, la définir plutôt comme une interface - Mettre dans une même interface des traitements
qui vont bien ensemble (séparer en deux sil le
faut) - Réfléchir aux traitements génériques dont on a
besoin, les réaliser en manipulant des
interfaces, puis implémenter ces interfaces. - Cest un principe fondamental pour la
réutilisation des traitements génériques - Dès quon a de lhéritage multiple, utiliser des
interfaces
32Les problèmes de l'héritage
33Polymorphisme les problèmes
- Les problèmes liés au polymorphisme sont dus au
fait que l'héritage ne sapplique pas
correctement à la signature des méthodes - Java ne retrouve pas le vrai type
- des paramètres
- des valeurs de retour
34Surcharge (rappel)
- On appelle surcharge le fait davoir plusieurs
méthodes qui ont le même nom au sein de la même
classe - Les exemplaires de la méthode ont des paramètres
différents - Ils peuvent avoir le même type de retour
- Par contre, impossible davoir des types de
retour différents pour les mêmes paramètres
35Surcharge exemple
- class Additionneur
- static int somme(int a, int b) // 1
-
- return (ab)
-
- static int somme(int a, int b, int c) // 2
-
- return (abc)
-
- static float somme(float a, float b) // 3
-
- return (ab)
-
- static float somme(int a, int b) // interdit à
cause de 1 -
- return ((float)a(float)b)
-
36Redéfinition
- On appelle redéfinition dune méthode le fait de
définir dans une classe fille une méthode qui a
le même nom, les mêmes paramètres et le même type
de retour quune méthode de la classe mère - La méthode redéfinie masque celle de la
classe mère - Ne pas confondre avec surcharge paramètres
identiques vs. différents
37Redéfinition exemple
- class Personne
- void garer(Vehicule v)
-
- v.demarrer()
- //
-
-
- class Garagiste extends Personne
- void garer(Vehicule v)
-
- v.fermerCapot() // appelle getCapot().fermer()
- v.demarrer()
- //
-
- Les deux méthodes ont la même signature et
appartiennent à deux classes liées par héritage
gt il s'agit de redéfinition
38Surcharge / redéfinition exemple
- class Additionneur
- static int somme(int a, int b)
-
- return (ab)
-
- static int somme(int a, int b, int c)
-
- return (abc)
-
-
- Dans Additionneur, les deux méthodes somme()
appartiennent à la même classe mais n'ont pas la
même signature gt il s'agit de surcharge - Dans Adder, on redéfinit la seconde méthode de
Additionneur
class Adder extends Additionneur static int
somme(int a, int b, int c) return
(2abc)
39Surcharge ou redéfinition ?
- class Personne
- void garer(Vehicule v)
-
- v.demarrer()
- //
-
-
- class Garagiste extends Personne
- void garer(Voiture v)
-
- v.fermerCapot() // appelle getCapot().fermer()
- v.demarrer()
- //
-
40Redéfinition et Surcharge
- Quand il y a des paramètres différents, mais qui
héritent les uns des autres - Ils sont vus comme effectivement différents
- Cest donc un cas de surcharge
- La méthode appelée sera celle dont les paramètres
sont du type le plus spécialisé qui correspondent
au type dappel - Le choix est fait à la compilation
- Des exemples seront vus en TD
41Hiérarchies complexesVers les Design Patterns
42Les hiérarchies complexes (1)
Vehicule
VehiculeAXRoues
VehiculeA2Roues
VehiculeA4Roues
Rollers
Mobylette
Voiture
Camion
Trottinette
Velo
Fourgonnette
Exemple de mauvais critère de classification le
nombre de roues Les descendants ont peu de chose
en commun
43Les hiérarchies complexes (2)
Vehicule
VehiculeAMoteur
VehiculeSansMoteur
Fourgonnette
Mobylette
Voiture
Camion
Trottinette
Velo
Rollers
Cette fois, le critère est structurant
44Les hiérarchies complexes (3)
VehiculeSansMoteur
VehiculeAMoteur
Moteur monMoteur int nbRoues Clef
maClef demarrer()
int nbRoues propulser()
Si lon est amené à modifier une hiérarchie
complexe cela implique des réorganisations
majeures du code En particulier, des attributs et
des traitements doivent être partagés Importance
de la phase de conception préalable
45Héritage et composition
46Intérêt de lhéritage
- class Sequenceur
-
- MonVecteur data
- public void reverse()
-
- data.reverse()
-
-
- class Sequenceur extends MonVecteur
-
- // pas besoin de public void reverse()
Sequenceur en hérite -
47Inconvénients de lhéritage
- Induit un couplage fort entre les classes de la
hiérarchie une modification de la classe mère
induit des modifications de toutes les filles - Ralentit lexécution à cause du typage dynamique
- Dans le livre Design patterns , vous trouverez
quantité darguments en faveur de lutilisation
des interfaces
48Vers les Design Patterns
- Dès quune application devient complexe
(plusieurs niveaux dabstraction, packages,
etc.), le coût de chaque remise en question
devient élevé - Les Design Patterns peuvent être vus comme un
ensemble de recettes utilisées très souvent et
destinées à minimiser ces coûts - En deuxième partie du cours POBJ