Grandes lignes du cours Cours JAVA : Le polymorphisme en Java. Version 3.05 Julien Sopena1 1 [email protected] Équipe REGAL - INRIA Rocquencourt LIP6 - Université Pierre et Marie Curie Licence professionnelle DANT - 2013/2014 J. Sopena (INRIA/UPMC) A B ... ... A B ... ... Le polymorphisme en Java. 1 / 121 Outline des limites à l’héritage L’héritage Redéfinition de méthode de Principes de l’héritage classe Syntaxe de l’héritage en Java Classes et méthodes Héritage et visibilité abstraites Héritage et construction Principes des classes La redéfinition abstraites La covariance Exemple de classe abstraite Interdire l’héritage Interfaces Polymorphisme et héritage Préambule et définition Principes du polymorphisme Déclaration et Protocoles et polymorphisme implémentation Les protocoles standards Polymorphisme d’interface Downcasting : la fin du Classe ou interface ? polymorphisme. Composition d’interfaces Le polymorphisme impose J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 2 / 121 Outline L’héritage Principes de l’héritage Syntaxe de l’héritage en Java Héritage et visibilité Héritage et construction La redéfinition La covariance Interdire l’héritage Polymorphisme et héritage Classes et méthodes abstraites Interfaces J. Sopena (INRIA/UPMC) Le polymorphisme en Java. L’héritage Principes de l’héritage Syntaxe de l’héritage en Java Héritage et visibilité Héritage et construction La redéfinition La covariance Interdire l’héritage Polymorphisme et héritage Classes et méthodes abstraites Interfaces 3 / 121 Rappel – principes de la POO J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 4 / 121 Un nouveau principe POO : Héritage Définition Le terme héritage désigne le principe selon lequel une classe peut hériter des caractéristiques (attributs et méthodes) d’autres classes. 1. Encapsulation I I Rapprochement des données (attributs) et traitements (méthodes) Protection de l’information (private et public) Soient deux classes A et B I 2. Agrégation (et composition) I I Classe A "A UN" Classe B I 3. Utilisation I Relation d’héritage : Classe B "EST UN" Classe A I Classe A "UTILISE" Classe B Exercice : Héritage, Agrégation ou Utilisation ? I I I I I J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 5 / 121 Motivation pour un nouveau type de relation entre classes J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 6 / 121 1. Faire que la classe Animal puisse vraiment représenter tous les animaux I Animal I +getNom(): String I +manger(...): ... +dormir(...): ... I +reproduire(...): ... I Problèmes pour implémenter cette spécification : I Elle est trop générale (exemple : manger( ) est très différent suivant les animaux) I Il manque les services spécifiques à certaines catégories d’animaux (exemple : voler( ), nager( ), ...) Le polymorphisme en Java. Cercle et Ellipse ? Salle de bains et Baignoire ? Piano et Joueur de piano ? Entier et Réel ? Personne, Enseignant et Étudiant ? Les mauvaises solutions Une classe décrit les services (comportements et données) d’un ensemble d’individus Exemple : la classe Animal (animation graphique) J. Sopena (INRIA/UPMC) A est la super-classe ou classe mère de B B est la sous-classe ou classe fille de A accroître l’interface publique (tous les services possibles de tous les animaux) ajouter des attributs booléens pour les catégories (isOiseau, isPoisson, ...) ou un attribut qui indique la catégorie tester les attributs pour savoir si on peut répondre à un message Exemple : Animal unChat = new Animal ("chat",...); (avec un attribut genreAnimal de type String dans la classe Animal) code très complexe et non maintenable 2. Faire autant de classes qu’il existe d’espèces animales I I 7 / 121 beaucoup de services vont être très similaires entre les classes beaucoup de factorisations perdues J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 8 / 121 Classification hiérarchisée Héritage Animal Vertébré Une sous-classe hérite des services (comportements et données) de ses ascendants I Pour factoriser au mieux la programmation, il suffit de placer les services à la bonne place dans la relation d’héritage setNom() getNom() Animal Reptile Poisson Mammifère Homme Invertébré I remuerVertèbres()Vertébré Chat I Les sous-classes (spécialisations) de la classe Mammifère sont les classes Homme et Chat I Les ascendants (généralisations) de la classe Mammifère sont les classes Vertébré et Animal J. Sopena (INRIA/UPMC) Le polymorphisme en Java. allaiter()Mammifère écrire() Homme 9 / 121 Hiérarchie en Java Une classe hérite toujours d’une seule et unique classe (héritage simple versus héritage multiple) I Cette classe est dite super-classe de la sous-classe I Par défaut, toute classe hérite de la classe Object qui est la racine unique de l’arbre d’héritage Object Animal Vertébré J. Sopena (INRIA/UPMC) Poisson nager() Chat Le polymorphisme en Java. 10 / 121 Outline I Mammifère J. Sopena (INRIA/UPMC) Invertébré Poisson Question ... Invertébré L’héritage Principes de l’héritage Syntaxe de l’héritage en Java Héritage et visibilité Héritage et construction La redéfinition La covariance Interdire l’héritage Polymorphisme et héritage Classes et méthodes abstraites Interfaces Reptile Le polymorphisme en Java. 11 / 121 Syntaxe J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 12 / 121 Spécialisation Pour indiquer qu’une classe hérite d’une autre classe, on utilise le mot-clé extends. p u b l i c class Logement { f i n a l p u b l i c double s u r f a c e ; p u b l i c double p r i x ; public S t r i n g p r o p r i e t a i r e ; p r i v a t e boolean vendu ; } p u b l i c class Appartement extends Logement p u b l i c class Appartement extends Logement { f i n a l public i n t etage ; p r i v a t e boolean c a v e ; } Important La classe Appartement ainsi définie possède toutes les caractéristiques de la classe Logement (i.e., ses éléments privés et publics). Les attributs de la classe Appartement sont : surface, prix, proprietaire, vendu, etage et cave. J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 13 / 121 Implémentation en Java 14 / 121 Durant l’exécution, l’instruction : unHomme . setNom ( "Adam" ) ; provoque : Homme unHomme = new Homme ( . . . ) ; // a p p e l d ’ un s e r v i c e p r o p r e aux hommes unHomme . é c r i r e ( ) ; // a p p e l d ’ un s e r v i c e commun aux v e r t é b r é s ( h é r i t é ) unHomme . r e m u e r V e r t è b r e s ( ) ; // a p p e l d ’ un s e r v i c e commun aux animaux ( h é r i t é ) unHomme . setNom ( "Adam" ) ; Le polymorphisme en Java. Le polymorphisme en Java. Héritage de comportements p u b l i c class Homme extends Mammifère { // a t t r i b u t s p r o p r e s aux hommes u n i q u e m e n t p r i v a t e boolean d r o i t i e r ; ... p u b l i c void é c r i r e ( ) { i f d r o i t i e r { . . . } else { . . . } } } J. Sopena (INRIA/UPMC) J. Sopena (INRIA/UPMC) I La recherche de setNom() dans la classe Homme I Puisqu’elle n’existe pas, la recherche se poursuit en remontant l’arbre d’héritage jusqu’à trouver Animal.setNom() I Animal.setNom() est exécutée (dans le contexte de unHomme) Si la méthode Animal.setNom() n’était pas définie, une erreur serait détectée lorsque la classe Object serait atteinte 15 / 121 J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 16 / 121 À retenir : le mot-clé super À retenir : la classe Object Important En Java, toutes les classes héritent de la classe Object. Á retenir Java fournit la référence super qui désigne pour chaque classe, sa classe mère. La déclaration p u b l i c class A { . . . } doit donc être comprise comme p u b l i c class A extends O b j e c t { . . . } même si on ne l’écrit pas ainsi. J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 17 / 121 Héritage d’attributs Le polymorphisme en Java. 18 / 121 Héritage d’attributs – suite p u b l i c class Animal { // a t t r i b u t s p r o p r e s à t o u s l e s animaux p r i v a t e S t r i n g nom ; . . . p u b l i c S t r i n g getNom ( ) { r e t u r n nom ; } p u b l i c void setNom ( S t r i n g n ) { nom = n ; } ... } p u b l i c class V e r t é b r é extends Animal { // a t t r i b u t s p r o p r e s aux V e r t é b r é s private int nbVertèbres ; . . . p u b l i c void s e t N b V e r t è b r e s ( i n t n ) { nbVertèbres = n ; } p u b l i c void r e m u e r V e r t è b r e s ( ) { System . o u t . p r i n t l n ( this.getNom() + " remue " + nbVertèbres + " vertèbres " ) ; } } J. Sopena (INRIA/UPMC) J. Sopena (INRIA/UPMC) Le polymorphisme en Java. p u b l i c class Homme extends Mammifère { // a t t r i b u t s p r o p r e s aux hommes u n i q u e m e n t p r i v a t e boolean d r o i t i e r ; ... p u b l i c Homme ( S t r i n g unNom , boolean d r o i t i e r ) { this.setNbVertebres(50) ; this.setNom(unNom) ; this . d r o i t i e r = d r o i t i e r ; } ... } 19 / 121 Héritage d’attributs – fin J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 20 / 121 Outline L’héritage Principes de l’héritage Syntaxe de l’héritage en Java Héritage et visibilité Héritage et construction La redéfinition La covariance Interdire l’héritage Polymorphisme et héritage Classes et méthodes abstraites Interfaces Homme uneFemme = new Homme( "È v e " , t r u e ) ; uneFemme Ève true 50 uneFemme . r e m u e r V e r t è b r e s ( ) ; System . o u t . p r i n t l n ( uneFemme . getNom ( ) ) ; J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 21 / 121 Héritage et encapsulation I Les membres (attributs et méthodes) déclarés privés dans une classe ne sont pas visibles dans une sous-classe I En d’autres termes, l’héritage n’implique pas la visibilité Le polymorphisme en Java. Le polymorphisme en Java. 22 / 121 Visibilité Le modificateur qui précède chaque méthode (et attribut) détermine sa visibilité : la classe elle-même une sous-classe, paquetage = pas une sous-classe, paquetage = une sous-classe, paquetage 6= pas une sous-classe, paquetage 6= p u b l i c class Homme extends Mammifère { // a t t r i b u t s p r o p r e s aux hommes u n i q u e m e n t p r i v a t e boolean d r o i t i e r ; ... p u b l i c Homme ( S t r i n g unNom , boolean d r o i t i e r ) { this . setNbVertebres (50); nom = unNom ; // e r r e u r this . d r o i t i e r = d r o i t i e r ; } ... } J. Sopena (INRIA/UPMC) J. Sopena (INRIA/UPMC) private défaut protected public OUI NON NON NON NON OUI OUI OUI NON NON OUI OUI OUI OUI NON OUI OUI OUI OUI OUI Rappel Les attributs doivent toujours être déclarés private 23 / 121 J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 24 / 121 Outline Instantiation des attributs hérités p u b l i c class Homme extends Mammifère { // a t t r i b u t s p r o p r e s aux hommes u n i q u e m e n t p r i v a t e boolean d r o i t i e r ; ... p u b l i c Homme ( S t r i n g unNom , boolean d r o i t i e r ) { this.setNbVertèbres(50) ; this.setNom(unNom) ; this . d r o i t i e r = d r o i t i e r ; } ... } L’héritage Principes de l’héritage Syntaxe de l’héritage en Java Héritage et visibilité Héritage et construction La redéfinition La covariance Interdire l’héritage Polymorphisme et héritage Classes et méthodes abstraites Interfaces J. Sopena (INRIA/UPMC) Problèmes Le polymorphisme en Java. 25 / 121 Héritage et construction – Correction I Obligation d’introduire des modificateurs telles que Vertébré.setNbVertèbres() I Redondance – la super-classe Mammifère doit avoir un constructeur J. Sopena (INRIA/UPMC) Règles p u b l i c class Homme extends Mammifère { p r i v a t e s t a t i c f i n a l i n t NB_VERTEBRES = 5 0 ; p r i v a t e boolean d r o i t i e r ; 1. L’appel d’un constructeur de la classe mère doit être la première instruction du constructeur de la classe fille. 2. Il n’est pas possible d’utiliser à la fois un autre constructeur de la classe et un constructeur de sa classe mère dans la définition d’un de ses constructeurs. p u b l i c Homme ( S t r i n g unNom , boolean d r o i t i e r , int nbVertèbres ) { // s u p e r d o i t ê t r e l a p r e m i è r e i n s t r u c t i o n super ( unNom , n b V e r t è b r e s ) ; this . d r o i t i e r = d r o i t i e r ; } p u b l i c class A { p u b l i c A( i n t x ) { super ( ) ; this ( ) ; } } p u b l i c Homme ( S t r i n g unNom , boolean d r o i t i e r ) { t h i s ( unNom , d r o i t i e r , NB_VERTEBRES ) ; } IT D ER T } Le polymorphisme en Java. 26 / 121 Règles d’utilisation d’un constructeur de la classe mère. Pour initialiser les attributs hérités, le constructeur d’une classe peut invoquer un des constructeurs de la classe mère à l’aide du mot-clé super. J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 27 / 121 Constructeur implicite IN J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 28 / 121 Constructeur implicite : exemple Si aucun constructeur de la classe ou de la super-classe n’est invoqué explicitement, le compilateur ajoute un appel au constructeur sans argument de la super-classe p u b l i c class A { p u b l i c A ( ) { System . o u t . p r i n t l n ( "A" ) ; } } p u b l i c class B extends A { p u b l i c B ( ) { System . o u t . p r i n t l n ( "B" ) ; } } p u b l i c class B extends A { p u b l i c B( i n t x ) { // a p p e l s u p e r ( ) i m p l i c i t e this . x = x ; ... } } Le ligne de code suivante : B c = new B ( ) ; produira l’affichage suivant : java MonProg A B Attention : Dans ce cas, le constructeur sans argument doit être défini dans la super-classe J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 29 / 121 Constructeur implicite : erreur fréquente Etape 1 : Jusqu’ici tout va bien. p u b l i c class A { public i n t x ; } p u b l i c class B extends A { public i n t y ; public B ( i n t x , i n t y ) { this . x = x ; this . y = y ; } } J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 30 / 121 Constructeur implicite : erreur fréquente Etape 2 : Puis, on ajoute un constructeur. p u b l i c class A { public i n t x ; public A (int x) { this.x =x; } } p u b l i c class B extends A { public i n t y ; public B ( i n t x , i n t y ) { this . x = x ; this . y = y ; } } Le polymorphisme en Java. J. Sopena (INRIA/UPMC) 31 / 121 javac B.java B.java:3: cannot find symbol symbol : constructor A() location: class A public B ( int x , int y ) { ^ 1 error } p u b l i c class B extends A { public i n t y ; public B ( i n t x , i n t y ) { super() ; \\ A j o u t du c o m p i l a t e u r this . x = x ; this . y = y ; } } J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 32 / 121 Constructeur implicite : Solutions Solution 1 : Ajout d’un constructeur vide. p u b l i c class A { public i n t x ; public A () {} public A ( i n t x ) { this . x = x ; } } Solution 2 : Appel explicite au super(int). p u b l i c class B extends A { public i n t y ; public B ( i n t x , i n t y ) { super(x); this . y = y ; } } Le polymorphisme en Java. Un constructeur d’une classe dérivée commence toujours : 1. soit par l’appel explicite d’un autre constructeur de la classe. 2. soit par l’appel explicite ou implicite d’un constructeur de la classe mère. p u b l i c class A { public i n t x ; public A ( i n t x ) { this . x = x ; } } p u b l i c class B extends A { public i n t y ; public B ( i n t x , i n t y ) { this . x = x ; this . y = y ; } } J. Sopena (INRIA/UPMC) Constructeur d’une classe dérivée 33 / 121 Outline Corollaire Comme tout objet dérive (directement ou indirectement) de la classe Object : Tout constructeur commence par exécuter le constructeur de l’Object J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 34 / 121 Définition de la redéfinition. Définition L’héritage Principes de l’héritage Syntaxe de l’héritage en Java Héritage et visibilité Héritage et construction La redéfinition La covariance Interdire l’héritage Polymorphisme et héritage Classes et méthodes abstraites Interfaces J. Sopena (INRIA/UPMC) Le polymorphisme en Java. On appelle redéfinition (en anglais « overriding ») d’une méthode, la possibilité de définir le comportement d’une méthode selon le type d’objet l’invoquant, i.e., de donner une nouvelle implémentation à une méthode héritée sans changer sa signature. p u b l i c class public i n t ... } } p u b l i c class public i n t ... } } 35 / 121 La signature d’une méthode Java 37 / 121 Le polymorphisme en Java. 36 / 121 J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 38 / 121 Spécialiser une méthode héritée On peut aussi surcharger une méthode redéfinie. La référence super permet de redéfinir une méthode f héritée en réutilisant sa définition dans la classe mère. On dit alors qu’on spécialise la méthode héritée f. p u b l i c class Logement { p u b l i c void v e n d r e ( S t r i n g a c q u e r e u r ) { this . p r o p r i e t a i r e = acquereur ; t h i s . vendu = t r u e ; } } p u b l i c class A { p u b l i c void f ( ) { ... } } p u b l i c class Appartement extends Logement { p u b l i c void v e n d r e ( S t r i n g a c q u e r e u r ) { this ( acquereur ) ; this . cave = false : } p u b l i c void v e n d r e ( S t r i n g a c q u e r e u r , boolean c a v e ) { this ( acquereur ) ; this . cave = cave : } } Le polymorphisme en Java. J. Sopena (INRIA/UPMC) Il ne faut pas confondre la redéfinition (en anglais « overriding ») et la surcharge (en anglais « overloading ») qui a été étudiée dans le cours d’introduction et qui correspond à la possibilité de définir des comportements différents pour la même méthode selon les arguments passés en paramètres. Surcharge d’une méthode redéfinie J. Sopena (INRIA/UPMC) B extend A { f (int x) { ATTENTION p u b l i c class L e o n a r d extends Homme { ... p u b l i c void dessiner () { System . o u t . p r i n t l n ( " J o c o n d e " ) ; } } Le polymorphisme en Java. { Overloading vs Overriding p u b l i c class Homme extends Mammifère { ... p u b l i c void dessiner () { System . o u t . p r i n t l n ( " G r i b o u i l l i s " ) ; } } J. Sopena (INRIA/UPMC) A { f (int x) p u b l i c class B extends A { p u b l i c void f ( ) { ... super.f() ... } } 39 / 121 J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 40 / 121 Spécialiser une méthode héritée : exemple Limite pour désigner une méthode redéfinie p u b l i c class P o i n t { private int x , y ; ... public S t r i n g t o S t r i n g ( ) { return " ( " + x + " , " + y + " ) " ; } } Attention On ne peut remonter plus haut que la classe mère pour récupérer une méthode redéfinie : p u b l i c class P o i n t C o u l e u r extends P o i n t { p r i v a t e byte c o u l e u r ; ... public S t r i n g t o S t r i n g ( ) { r e t u r n super . t o S t r i n g ( ) + "\ nCouleur ␣ : ␣" + t h i s . c o u l e u r ; } } J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 41 / 121 Annotation pour la redéfinition I pas de cast (ClasseAncetre)m() I pas de super.super.m() J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 42 / 121 Outline Depuis Java 5, on peut annoter par @Override les redéfinitions de méthodes. Ceci est très utile pour repérer des fautes de frappe dans le nom de la méthode : le compilateur envoie un message d’erreur si la méthode ne redéfinit aucune méthode. p u b l i c class P o i n t { private int x , y ; ... @Override public S t r i n g t o s t r i n g ( ) { return " ( " + x + " , " + y + " ) " ; } } L’héritage Principes de l’héritage Syntaxe de l’héritage en Java Héritage et visibilité Héritage et construction La redéfinition La covariance Interdire l’héritage Polymorphisme et héritage Classes et méthodes abstraites Interfaces Point.java:3: method does not override or implement a method from a supertype @Override ˆ J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 43 / 121 Les fondements de la covariance 2. La signature d’une méthode est composée de son nom et des types de ses arguments. Définition On appelle covariance le fait de modifier le type de retour d’une méthode lors de sa redéfinition. En Java, elle a été introduite dans la version : Java 1.5. 45 / 121 classes finales J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 46 / 121 Méthodes finales On peut empêcher la redéfinition d’une méthode d’instance d’une classe dans une de ses sous-classes en la déclarant final. Lors de la conception d’une classe, le concepteur peut empêcher que d’autres classes héritent d’elle (classe finale). p u b l i c class A { f i n a l p u b l i c void f ( ) {} } f i n a l p u b l i c class A { } Remarque(s) La classe String est une classe finale. J. Sopena (INRIA/UPMC) 44 / 121 L’héritage Principes de l’héritage Syntaxe de l’héritage en Java Héritage et visibilité Héritage et construction La redéfinition La covariance Interdire l’héritage Polymorphisme et héritage Classes et méthodes abstraites Interfaces 1. La redéfinition d’une méthode c’est le fait de donner une nouvelle implémentation en conservant la signature. Le polymorphisme en Java. Le polymorphisme en Java. Outline Rappels J. Sopena (INRIA/UPMC) J. Sopena (INRIA/UPMC) Le polymorphisme en Java. p u b l i c class B extends A { // on ne p e u t p a s r e d é f i n i r f ( ) ! } 47 / 121 J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 48 / 121 Outline Outline L’héritage Polymorphisme et héritage Principes du polymorphisme Protocoles et polymorphisme Les protocoles standards Downcasting : la fin du polymorphisme. Le polymorphisme impose des limites à l’héritage Redéfinition de méthode de classe Classes et méthodes abstraites Interfaces J. Sopena (INRIA/UPMC) Le polymorphisme en Java. L’héritage Polymorphisme et héritage Principes du polymorphisme Protocoles et polymorphisme Les protocoles standards Downcasting : la fin du polymorphisme. Le polymorphisme impose des limites à l’héritage Redéfinition de méthode de classe Classes et méthodes abstraites Interfaces 49 / 121 Polymorphisme : définition J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 50 / 121 Principe POO : Polymorphisme Si la classe B hérite de la classe A I Classe B "EST-UN" Classe A I toute méthode m de A peut-être invoquée sur une instance de la classe B (+ transitivité sur l’héritage de A) Le polymorphisme consiste à exploiter cela en fournissant un B dans les expressions "qui attendent" un A. Définition Le polymorphisme peut être vu comme la capacité de choisir dynamiquement la méthode qui correspond au type réel de l’objet. // un homme e s t un a n i m a l Animal anim1 = new Homme( " Caïn " , f a l s e ) ; // un c h a t a u s s i Animal anim2 = new Chat ( " E u r o p é e n " ) ; System . o u t . p r i n t l n ( anim1 . getNom ( ) ) ; System . o u t . p r i n t l n ( anim2 . getNom ( ) ) ; // un a n i m a l n ’ e s t p a s n é c e s s a i r e m e n t un homme Homme h = anim1 J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 51 / 121 Choix de la méthode : liaison dynamique p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) { P o i n t [ ] t a b = new P o i n t [ 3 ] ; t a b [ 0 ] = new PointCouleur ( 2 , 3 , b l e u ) ; t a b [ 1 ] = new PointCouleur ( 2 , 3 , v e r t ) ; t a b [ 2 ] = new PointCouleur ( 2 , 3 , r o u g e ) ; System . o u t . p r i n t l n ( "Ma␣ l i g n e ␣ : ␣ " ) ; for ( Point p : tab ) System . o u t . p r i n t l n ( " ␣−␣ " + p . toString ( ) ) ; } } } 53 / 121 Choix de la méthode : liaison dynamique (suite) J. Sopena (INRIA/UPMC) 1. La méthode toString() est définie dans Point 54 / 121 Écrire du code polymorphe : le problème p u b l i c class Zoo { p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) { Cage uneCage1 = new Cage ( . . . ) ; Cage uneCage2 = new Cage ( . . . ) ; 2. Mais elle est spécialisée dans PointCouleur C’est la version la plus spécialisée (PointCouleur.toString()) qui est invoquée car la recherche de la méthode débute dans la classe effective de l’objet référencé par p // On a j o u t e un l i o n L i o n u n L i o n = new L i o n ( . . . ) ; uneCage1 . a c c u e i l l i r ( u n L i o n ) ; La recherche est menée à l’exécution et ce mécanisme est appelé la liaison dynamique. Lorsqu’une méthode est spécialisée dans une sous-classe, sa visibilité peut être augmentée (ex. protected → public) mais elle ne peut pas être réduite (ex. public 6→ private) Le polymorphisme en Java. Le polymorphisme en Java. On veut coder une classe Zoo qui aura plusieurs cages permettant d’acceuillir différents types d’animaux. Il faut donc implémenter une classe Cage permettant de contenir tous ces annimaux. Si p référence une PointCouleur, quelle méthode toString() va être invoquée ? J. Sopena (INRIA/UPMC) 52 / 121 p u b l i c class T r a c e u r D e L i g n e { p u b l i c class P o i n t C o u l e u r extends P o i n t { p r i v a t e byte c o u l e u r ; ... public S t r i n g t o S t r i n g ( ) { r e t u r n super . t o S t r i n g ( ) + "\ nCouleur ␣ : ␣" + t h i s . c o u l e u r ; } } Le polymorphisme en Java. Le polymorphisme en Java. Choix de la méthode : liaison dynamique (suite) p u b l i c class P o i n t { private int x , y ; ... public S t r i n g t o S t r i n g ( ) { return " ( " + x + " , " + y + " ) " ; } } J. Sopena (INRIA/UPMC) J. Sopena (INRIA/UPMC) ; // On a j o u t e un s i n g e S i n g e u n S i n g e = new S i n g e ( . . . ) ; uneCage2 . a c c u e i l l i r ( u n S i n g e ) ; } } 55 / 121 J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 56 / 121 Écrire du code polymorphe : la mauvaise solution La bonne solution consiste à utiliser le polymorphisme, en implémentant une méthode acceuillir générique pour tout les animaux. p u b l i c class Cage { p u b l i c void a c c u e i l l i r ( L i o n l ) { ... } p u b l i c void a c c u e i l l i r ( S i n g e s ) { ... } } Son paramètre étant de type Animal on pourra l’appeler avec une référence de Lion ou de Singe. p u b l i c class Cage { p u b l i c void a c c u e i l l i r ( Animal a ) { System . o u t . p r i n t l n ( a . getNom ( ) + " e s t ␣ en ␣ c a g e " ) ; ... } } Ici, la surcharge est une très mauvaise solution I Si une nouvelle espèce animale doit être prise en compte, il faudra modifier le code de la classe Cage J. Sopena (INRIA/UPMC) Écrire du code polymorphe : la bonne solution Le polymorphisme en Java. 57 / 121 Outline J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 58 / 121 Motivation L’héritage Polymorphisme et héritage Principes du polymorphisme Protocoles et polymorphisme Les protocoles standards Downcasting : la fin du polymorphisme. Le polymorphisme impose des limites à l’héritage Redéfinition de méthode de classe Classes et méthodes abstraites Interfaces J. Sopena (INRIA/UPMC) Nouvelle spécification à prendre en compte : tous les animaux ne peuvent pas aller en cage La méthode Cage.accueillir() doit être à même de détecter les animaux ne pouvant l’être p u b l i c class Zoo { p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) { Cage uneCage1 = new Cage ( . . . ) ; Homme unHomme = new Homme ( . . . ) ; uneCage . a c c u e i l l i r (unHomme ) ; =⇒ il refuse !!! } } Le polymorphisme en Java. 59 / 121 Première solution J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 60 / 121 Mise en place d’un protocole p u b l i c class Cage { ... p u b l i c void a c c u e i l l i r ( Animal a ) { i f ( ! a . supporteCage ( ) ) { System . o u t . p r i n t ( a . getNom ( ) ) ; System . o u t . p r i n t l n ( " ␣ r e f u s e ␣d ’ a l l e r ␣ en ␣ c a g e " ) ; return ; } ... } } p u b l i c class Cage { ... p u b l i c void a c c u e i l l i r ( Animal a ) { i f ( a instanceof Homme ) System . o u t . p r i n t l n ( a . getNom ( ) + " r e f u s e ␣d ’ a l l e r ␣ en ␣ c a g e " ) ; return ; ... } } Très mauvaise solution I I Des connaissances propres à la classe Homme sont dans la classe Cage si une nouvelle espèce animale refuse d’aller en cage, il faudra modifier le code de la classe Cage J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 61 / 121 Vue de l’arbre d’héritage supporteCage() Vertébré ⇒ true supporteCage() Homme ⇒ false J. Sopena (INRIA/UPMC) Tout animal doit pouvoir répondre à ce protocole I Nous allons implémenter le protocole dans la hiérarchie de racine Animal, en utilisant l’héritage et en spécialisant lorsque c’est nécessaire J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 62 / 121 Mise en place d’un protocole public class Animal { ... p u b l i c boolean s u p p o r t e C a g e ( ) { r e t u r n f a l s e ; } } supporteCage() Animal ⇒ false Mammifère I Invertébré supporteCage() ⇒ false Poisson p u b l i c c l a s s Homme extends Mammifère { ... p u b l i c boolean s u p p o r t e C a g e ( ) { r e t u r n f a l s e ; } } p u b l i c c l a s s Zoo { p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) { Cage uneCage1 = new Cage ( . . . ) ; uneCage1 . a c c u e i l l i r ( new L i o n ( . . . ) ) ; // G é n è r e un a p p e l à V e r t é b r é . s u p p o r t e C a g e ( ) ; } } Lion Le polymorphisme en Java. p u b l i c c l a s s V e r t é b r é extends A n i m a l { ... p u b l i c boolean s u p p o r t e C a g e ( ) { r e t u r n t r u e ; } } 63 / 121 J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 64 / 121 Outline Retour sur les protocoles standards p u b l i c c l a s s Zoo { p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) { Cage [ 1 0 ] l e s C a g e s ; L i o n u n L i o n = new L i o n ( . . . ) ; l e s C a g e s [ 0 ] . a c c u e i l l i r ( unLion ) ; S i n g e u n S i n g e = new S i n g e ( . . . ) ; lesCages [ 1 ] . a c c u e i l l i r ( unSinge ) ; L’héritage Polymorphisme et héritage Principes du polymorphisme Protocoles et polymorphisme Les protocoles standards Downcasting : la fin du polymorphisme. Le polymorphisme impose des limites à l’héritage Redéfinition de méthode de classe Classes et méthodes abstraites Interfaces J. Sopena (INRIA/UPMC) Le polymorphisme en Java. f o r ( Cage c : l e s C a g e s ) { System . o u t . println(c.contenu()) ; i f ( u n L i o n . equals(c.contenu()) System . o u t . p r i n t l n ( " J ’ a i ␣ t r o u v e ␣ l e ␣ l i o n " ) ; } } } 65 / 121 Le protocole toString() p u b l i c c l a s s System { public s t a t i c PrintStream ... } public class PrintStream { p u b l i c v o i d p r i n t ( Object I La classe Lion ne dispose pas de méthode equals(), pourquoi n’y a-t-il pas d’erreur de compilation ? I Où est l’appel la méthode toString() de Animal ? J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 66 / 121 Le protocole toString() – suite out ; I La classe Object est la racine de l’unique arbre d’héritage I La classe Animal hérite (implicitement) de la classe Object I Il suffit de spécialiser la méthode toString() dans vos classes pour qu’un objet de type PrintStream (tel que System.out) puisse afficher vos instances arg ) { p r i n t ( a r g . toString() ) ; } ... p u b l i c class Animal ... } { @Override public S t r i n g t o S t r i n g ( ) { r e t u r n t h i s . getNom ( ) ; } p u b l i c c l a s s Object { p u b l i c S t r i n g toString ( ) { r e t u r n g e t C l a s s ( ) . getName ( ) + "@" + I n t e g e r . t o H e x S t r i n g ( h a s h C o d e ( ) ) ; } ... } } J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 67 / 121 Le protocole equals() J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 68 / 121 Le protocole equals() – suite Le protocole equals() est employé dans les paquetages standards pour comparer les objets entre eux Extrait de la documentation de java.util.Arrays : La classe Object dispose d’une méthode equals() p u b l i c s t a t i c boolean e q u a l s ( O b j e c t [ ] a , O b j e c t [ ] a2 ) p u b l i c class Object { p u b l i c boolean equals ( O b j e c t a r g ) { r e t u r n t h i s == a r g ; } ... } Returns true if the two specified arrays of Objects are equal to one another. The two arrays are considered equal if both arrays contain the same number of elements, and all corresponding pairs of elements in the two arrays are equal. Two objects e1 and e2 are considered equal if Elle ne retourne true que si les deux références désignent le même objet ( e1==n u l l ? e2==n u l l : e1 . equals ( e2 ) ) In other words, the two arrays are equal if they contain the same elements in the same order. Also, two array references are considered equal if both are null. J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 69 / 121 Spécialisation de equals() dans vos classes Le polymorphisme en Java. Le polymorphisme en Java. 70 / 121 Outline p u b l i c class C o o r d o n n é e { private int x , y ; ... p u b l i c boolean e q u a l s ( O b j e c t o b j ) { // t e s t s u r l e s r é f é r e n c e s i f ( t h i s == o b j ) return true ; i f ( o b j == n u l l ) return false ; // t e s t s u r l e s c l a s s e s i f ( this.getClass ( ) != o b j . getClass ( ) ) return false ; // t e s t s u r l e s d o n n é e s C o o r d o n n é e o t h e r = (Coordonnée) obj ; r e t u r n ( t h i s . x == o t h e r . x && t h i s . y == o t h e r . y ) ; } } J. Sopena (INRIA/UPMC) J. Sopena (INRIA/UPMC) L’héritage Polymorphisme et héritage Principes du polymorphisme Protocoles et polymorphisme Les protocoles standards Downcasting : la fin du polymorphisme. Le polymorphisme impose des limites à l’héritage Redéfinition de méthode de classe Classes et méthodes abstraites Interfaces 71 / 121 J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 72 / 121 Upcasting : classe fille → classe mère Downcasting : classe mère → classe fille Définition Définition On appelle surclassement ou upcasting le fait d’enregistrer une référence d’une instance d’une classe B héritant d’une classe A dans une variable de type A. En java, cette opération est implicite et constitue la base du polymorphisme. On appelle déclassement ou downcasting le fait de convertir une référence « surclassée » pour « libérer » certaines fonctionnalités cachées par le surclassement. En java, cette conversion n’est pas implicite, elle doit être forcée par l’oppérateur de cast : (<nomClasse>). p u b l i c class A { . . . } p u b l i c class A { . . . } p u b l i c class B extends A { . . . } p u b l i c class B extends A { . . . } A a = new B ( ) // C ’ e s t de l ’ u p c a s t i n g ( s u r c l a s s e m e n t ) . A a = new B ( ) ; // s u r c l a s s e m e n t , u p c a s t i n g B b = (B) a ; // d o w n c a s t i n g On dit que a1 est une référence surclassée (elle est du type A et contient l’adresse d’une instance d’une sous-classe de A). J. Sopena (INRIA/UPMC) Le polymorphisme en Java. Pour que la conversion fonctionne, il faut qu’à l’exécution le type réel de la référence à convertir soit B ou une des sous-classe de B ! 73 / 121 J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 74 / 121 Downcasting : utilisation de instanceof Downcasting : mise en garde ! On peut utiliser le mot-clé instanceof pour savoir si une référence d’une classe donnée ou d’une de ces sous-classes. Attention Le downcasting ne permet pas de convertir une instance d’une classe donnée en une instance d’une sous-classe ! Si a est une référence de type B alors l’expression a instanceof A renvoie true si B est une sous-classe de A et false sinon. a = new B ( ) ; i f ( a i n s t a n c e o f A) { System . o u t . p r i n t ( " a ␣ r é f é r e n c e ␣ un ␣A , " ) ; System . o u t . p r i n t l n ( " ou ␣ une ␣ s o u s ␣ c l a s s e ␣ de ␣A . " ) ; } class A { A ( ) {}} class B extends A { B ( ) {}} A a = new A ( ) ; B b = (B) a ; Remarque(s) Attention, l’utilisation d’instanceof est souvent la marque d’un défaut de conception et va à l’encontre du polymorphisme. Ça compile, mais ça plantera à l’exécution : Exception in thread "main" java.lang.ClassCastException: A cannot be cast to B J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 75 / 121 Exemple : classe rendant un service générique. J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 76 / 121 Exemple : polymorphisme d’héritage public class Garage { Ve hicu le [ ] tab ; int nbVehicules ; p u b l i c class V e h i c u l e { ... } Garage ( i n t t a i l l e ) { t a b = new V e h i c u l e [ t a i l l e ] ; nbVehicules = 0; } p u b l i c class Moto extends V e h i c u l e { ... } void e n t r e r V e h i c u l e ( V e h i c u l e v ) { i f ( n b V e h i c u l e s <t a b . l e n g t h ) t a b [ n b V e h i c u l e s ++] = v ; } p u b l i c class V o i t u r e extends V e h i c u l e { int temperature ; ... void a u g m e n t e r C h a u f f a g e ( i n t deg ) { t e m p e r a t u r e += deg ; } } Vehicule sortirVehicule () { i f ( n b V e h i c u l e s >0) r e t u r n t a b [−− n b V e h i c u l e s ] ; else return null ; } } J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 77 / 121 Exemple : le downcast c’est la fin du polymorphisme Le polymorphisme en Java. Le polymorphisme en Java. 78 / 121 Outline L’héritage Polymorphisme et héritage Principes du polymorphisme Protocoles et polymorphisme Les protocoles standards Downcasting : la fin du polymorphisme. Le polymorphisme impose des limites à l’héritage Redéfinition de méthode de classe Classes et méthodes abstraites Interfaces p u b l i c class Main { p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) { I n d i v i d u moi = new I n d i v i d u ( . . . ) ; G a r a g e monGarage = new G a ra g e ( 2 ) ; // Le p o l y m o r p h i s m e p e r m e t de g a r e r d e s // v é h i c u l e s s a n s s ’ o c c u p e r de l e u r s t y p e s . monGarage . e n t r e r V e h i c u l e (new Moto ( ) ) ; monGarage . e n t r e r V e h i c u l e (new V o i t u r e ( ) ) ; ... V e h i c u l e u n V e h i c u l e = monGarage . s o r t i r V e h i c u l e ( ) ; i f ( moi . a v o i r F r o i d ( ) ) { // S i on ne p a r t a g e p a s l e g a r a g e , on s a i t // qu ’ on v i e n t de s o r t i r une v o i t u r e (( Voiture ) unVehicule ) . augmenterChauffage ( 1 0 ) ; } } } J. Sopena (INRIA/UPMC) J. Sopena (INRIA/UPMC) 79 / 121 J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 80 / 121 Ce qu’on ne peut pas faire et ne pas faire Problème de la covariance Pour permettre le polymorphisme : Dans cet exemple de covariance, peut-on choisir Y librement ? =⇒ une sous classe doit pouvoir se faire passer pour une sur classeur ; p u b l i c class A { ... public X f ( i n t x ) { ... } } =⇒ une fille doit pouvoir le faire tout ce que fait sa mère ; On ne peut rien supprimer : I On ne peut pas supprimer un membre ; I Changer le type d’un attribut ; I On ne peut pas réduire la visibilité d’un membre ; I La covariance doit maintenir la compatibilité (voir suivants). p u b l i c class B extends A { ... @Override public Y f ( i n t x ) { ... } } Par contre on peut toujours ajouter/modifier des choses : I On peut ajouter des membres ; I On peut redéfinir des méthodes ; I On peut augmenter la visibilité d’un membre. J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 81 / 121 Problème de la covariance J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 82 / 121 Limite de la covariance Dans cet exemple de covariance, peut-on choisir Y librement ? p u b l i c class Main { s t a t i c void g (A a ) { ... X x = a . f (3); ... } p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) { A a = new A ( ) ; g(a ); a = new B ( ) ; // Q u e l l e v e r s i o n f s e r a e x e c u t é e d a n s c e t a p p e l ? g(a ); } } p u b l i c class A { ... public X f ( i n t x ) { ... } } p u b l i c class B extends A { ... @Override public Y f ( i n t x ) { ... } } C’est la verion de B qui sera executée : =⇒ La référence de Y retournée doit être "compatible" avec X =⇒ La classe Y doit être un descendant de de la classe X J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 83 / 121 Limite de la covariance 85 / 121 Overriding vs Hiding Le polymorphisme en Java. 86 / 121 public class Felide () { s t a t i c String rugir () { S y s t e m . o u t . p r i n t l n ( " Miaou ␣ ! ! ! " ) ; } } On appelle en anglais « hiding », la redéfinition d’une méthode de classe. Son comportement diffère de l’« Overriding » qui est une redéfinition d’une méthode d’instance. p u b l i c class Lion () { s t a t i c String rugir () { S y s t e m . o u t . p r i n t l n ( "GRRRRRR␣ ! ! ! " ) ; } } Contrairement aux méthodes d’instance, les appels aux méthodes de classe sont résolus statiquement à la compilation. p u b l i c c l a s s Savane { p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) { F e l i d e f = new L i o n ( ) ; S y s t e m . o u t . p r i n t l n ( " Le ␣ l i o n ␣ f a i t ␣ : ␣ " + f . r u g i r ( ) ) ; } } Si une instance est utilisée pour l’invocation, la classe utilisée sera celle du type déclaré et non du type réel de l’objet. =⇒ Il n’y a pas de polymorphisme sur les méthodes de classe Le polymorphisme en Java. J. Sopena (INRIA/UPMC) Tout est décidé statiquement Définition J. Sopena (INRIA/UPMC) 84 / 121 L’héritage Polymorphisme et héritage Principes du polymorphisme Protocoles et polymorphisme Les protocoles standards Downcasting : la fin du polymorphisme. Le polymorphisme impose des limites à l’héritage Redéfinition de méthode de classe Classes et méthodes abstraites Interfaces Lorsque l’on fait de la redéfinition avec covariance, le nouveau type de retour doit toujours être un sous-type du type de retour original. Le polymorphisme en Java. Le polymorphisme en Java. Outline Règle de covariance J. Sopena (INRIA/UPMC) J. Sopena (INRIA/UPMC) 87 / 121 java Savane J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 88 / 121 Tout est décidé statiquement Outline public class Felide () { s t a t i c String rugir () { S y s t e m . o u t . p r i n t l n ( " Miaou ␣ ! ! ! " ) ; } } L’héritage Polymorphisme et héritage Classes et méthodes abstraites Principes des classes abstraites Exemple de classe abstraite Interfaces p u b l i c class Lion () { s t a t i c String rugir () { S y s t e m . o u t . p r i n t l n ( "GRRRRRR␣ ! ! ! " ) ; } } p u b l i c c l a s s Savane { p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) { F e l i d e f = new L i o n ( ) ; S y s t em . o u t . p r i n t l n ( " Le ␣ l i o n ␣ f a i t ␣ : ␣ " + f . r u g i r ( ) ) ; } } java Savane Le lion fait : Miaou !!! J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 88 / 121 Outline J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 89 / 121 Motivation p u b l i c class A n i m a t i o n { ... p u b l i c void f a i r e M a n g e r ( Animal a , N o u r r i t u r e n ) { ... a . manger ( n ) ; ... } ... } L’héritage Polymorphisme et héritage Classes et méthodes abstraites Principes des classes abstraites Exemple de classe abstraite Interfaces J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 90 / 121 Spécification d’un protocole sans implémentation par défaut I Il faut introduire une méthode manger() dans la classe Animal pour que cela compile I problème =⇒ quel comportement y décrire puisque la façon de manger dépend de l’espèce animale ? J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 91 / 121 Méthodes abstraites =⇒ Classe abstraite Spécification du protocole – le plus haut possible dans l’arbre d’héritage p u b l i c abstract class Animal { ... p u b l i c abstract void manger ( N o u r r i t u r e n ) ; // p a s de c o d e a s s o c i é ... } Définition Un classe contenant au moins une méthode abstraite est appelée une classe abstraite et cela doit être explicitement précisé dans la déclaration avec : abstract class Remarque(s) Spécialisation du protocole – là où c’est nécessaire dans l’arbre d’héritage p u b l i c class L i o n extends Mammifère { ... p u b l i c void manger ( N o u r r i t u r e n ) { . . . // c o d e s p é c i f i q u e aux l i o n s } ... } J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 92 / 121 Classe abstraite : instanciation et spécialisation. I I Une classe abstraite peut contenir des méthodes concrètes. I Une classe peut être déclarée abstraite sans contenir de méthode abstraite. J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 93 / 121 Outline Une classe abstraite constitue un type à part entière : Animal unAnimal ; // OK I Une classe abstraite ne peut pas être instanciée, en effet son comportement n’est pas complètement défini : Animal unAnimal = new Animal ( . . . ) ; // ERREUR I Une sous-classe d’une classe abstraite peut implémenter toutes les méthodes abstraites de sa super-classe. Elle pourra alors être déclarée comme concrète et donc instanciée. I ne pas implémenter toutes ces méthodes abstraite. Elle reste alors nécessairement abstraite ( abstract class ) et ne pourra être instanciée. I ajouter d’autre(s) méthode(s) abstraite(s). Elle reste alors nécessairement abstraite ( abstract class ) et ne pourra être instanciée. (INRIA/UPMC) Le polymorphisme en Java. 94 / 121 L’héritage Polymorphisme et héritage Classes et méthodes abstraites Principes des classes abstraites Exemple de classe abstraite Interfaces I J. Sopena J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 95 / 121 Exemple : besoin Exemple : déclaration de la classe abstraite. p u b l i c a b s t r a c t class F i g u r e { p r i v a t e S t r i n g nom ; Considérons la hiérarchie de classes suivantes : aire() // Une c l a s s e a b s t r a i t e ne p e u t p a s ê t r e i n s t a n c i é e , // m a i s e l l e p e u t a v o i r un c o n s t r u c t e u r : p u b l i c F i g u r e ( S t r i n g nom ) { t h i s . nom=nom ; } Figure Cercle // V o i l à l a méthode a b s t r a i t e à c o m p l é t e r : p u b l i c a b s t r a c t double a i r e ( ) ; Rectangle Cahier de charge : on veut que toutes les classes disposent de la méthode aire() retournant l’aire de la figure géométrique définie par la classe. // T o u t e s l e s méthodes ne s o n t p a s a b s t r a i t e s : public S t r i n g q u i S u i s J e ( ) { System . o u t . p r i n t l n ( " Je ␣ s u i s ␣ un ␣ " + t h i s . nom ) ; } } J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 96 / 121 Exemple : première implémentation. J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 97 / 121 Exemple : deuxième implémentation. p u b l i c class R e c t a n g l e extends F i g u r e { p r i v a t e double l a r g e u r ; p r i v a t e double l o n g u e u r ; p u b l i c class C e r c l e extends F i g u r e { p r i v a t e double r a y o n ; p u b l i c C e r c l e ( double r a y o n ) { super ( " c e r c l e " ) ; this . rayon = rayon ; } p u b l i c R e c t a n g l e ( double l a r g e u r , double l o n g u e u r ) { super ( " r e c t a n g l e " ) ; this . largeur = largeur ; this . longueur = longueur ; } p u b l i c double a i r e ( ) { r e t u r n Double . PI ∗ t h i s . r a y o n ∗ t h i s . r a y o n ; } p u b l i c double a i r e ( ) { return this . l a r g e u r ∗ this . longueur ; } } } J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 98 / 121 Exemples du standard J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 99 / 121 Outline Extrait de la documentation de java.lang.Number : I The abstract class Number is the superclass of classes BigDecimal, BigInteger, Byte, Double, Float, Integer, Long, and Short. I Subclasses of Number must provide methods to convert the represented numeric value to byte, double, float, int, long, and short. L’héritage Polymorphisme et héritage Classes et méthodes abstraites Interfaces Préambule et définition Déclaration et implémentation Polymorphisme d’interface Classe ou interface ? Composition d’interfaces public abstract i n t i n t V a l u e ( ) ; p u b l i c a b s t r a c t long l o n g V a l u e ( ) ; public abstract f l o a t f l o a t V a l u e ( ) ; ... J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 100 / 121 Outline J. Sopena (INRIA/UPMC) 101 / 121 Préambule L’héritage Polymorphisme et héritage Classes et méthodes abstraites Interfaces Préambule et définition Déclaration et implémentation Polymorphisme d’interface Classe ou interface ? Composition d’interfaces Problèmes à résoudre : I assurer qu’un ensemble de classes offre un service minimum commun. I faire du polymorphisme avec des objets dont les classes n’appartiennent pas à la même hiérarchie d’héritage. I utilisation d’objets sans connaître leur type réel. Solution : I J. Sopena (INRIA/UPMC) Le polymorphisme en Java. Le polymorphisme en Java. 102 / 121 la définition d’un type complètement abstrait nommé interface (notion de contrat). J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 103 / 121 Définition Outline Quand toutes les méthodes d’une classe sont abstraites et qu’il n’y a aucun attribut, on aboutit à la notion d’interface. Définition I Une interface est un prototype de classe. Elle définit la signature des méthodes qui doivent être implémentées dans les classes construites à partir de ce prototype. I Une interface est une “classe” purement abstraite dont toutes les méthodes sont abstraites et publiques. Les mots-clés abstract et public sont optionnels. J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 104 / 121 Déclaration : syntaxe L’héritage Polymorphisme et héritage Classes et méthodes abstraites Interfaces Préambule et définition Déclaration et implémentation Polymorphisme d’interface Classe ou interface ? Composition d’interfaces J. Sopena (INRIA/UPMC) Comme les classes abstraites, les interfaces ne sont pas instanciables : p u b l i c i n t e r f a c e Comparable { p u b l i c a b s t r a c t boolean p l u s G r a n d ( O b j e c t o ) ; } I Une interface ne possède pas d’attribut instance. I Une interface n’a pas de constructeur. Le but des interfaces est définir des API : public interface Tracable { void d e s s i n e T o i ( ) ; void d e p l a c e T o i ( i n t x , i n t y ) ; } I toutes leurs méthodes sont public. Elles ne définissent pas les mécanismes internes I tout leurs attributs de classe sont des constante, c’est-à-dire définir des attributs déclarées comme public static final et ayant une valeur constante d’affectation. Exemple : public abstract int f(); Remarque(s) Dans les déclarations des méthodes de la classe Tracable, les mots clés public et abstract sont implicites, mais ce n’est pas recommandé. Le polymorphisme en Java. 106 / 121 Implémentation d’une interface public static final float PI = 3.14f; J. Sopena (INRIA/UPMC) 107 / 121 Attention On dit qu’une classe implémente une interface si elle définit l’ensemble des méthodes abstraites de cette interface. On utilise alors, dans l’entête de la classe, le mot-clé implements suivi du nom de l’interface implémetée. La classe doit implémenter toutes les méthodes de l’interface, sinon elle doit être déclarée abstract. class P e r s o n n e implements Comparable { p r i v a t e S t r i n g nom ; p r i v a t e S t r i n g prenom ; ... p u b l i c boolean p l u s G r a n d ( O b j e c t o ) { r e t u r n t h i s . nom . compareTo ( ( ( P e r s o n n e ) o ) . nom ) | | t h i s . prenom . compareTo ( ( ( P e r s o n n e ) o ) . prenom ) ; } } Le polymorphisme en Java. Le polymorphisme en Java. Implémentation d’une interface Définition J. Sopena (INRIA/UPMC) 105 / 121 Déclaration : règles La définition d’une interface se présente comme celle d’une classe, en utilisant le mot-clé interface à la place de class. J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 108 / 121 Outline abstract class C e r c l e implements T r a c a b l e { private i n t xCentre , yCentre ; private i n t rayon ; ... p u b l i c void d e p l a c e T o i ( i n t x , i n t y ) { x C e n t r e += x ; y C e n t r e += y ; } } J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 109 / 121 Utilisation comme type de données L’héritage Polymorphisme et héritage Classes et méthodes abstraites Interfaces Préambule et définition Déclaration et implémentation Polymorphisme d’interface Classe ou interface ? Composition d’interfaces Une interface peut remplacer une classe pour déclarer : I un attribut I une variable I un paramètre I une valeur de retour A l’exécution, la donnée correspond à une référence d’un objet dont la classe implémente l’interface. C’est suivant le type réel de cet objet que l’on choisira le code des méthodes à exécuter. J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 110 / 121 J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 111 / 121 Exemple d’utilisation comme type de données. Exemple de polymorphisme dans un tableau p u b l i c class L i s t e E l e m e n t s { Comparable [ ] t a b ; i n t nbElements = 0 ; ... p u b l i c class Main { p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) { Comparable v a r 1 , v a r 2 ; ... i f ( var1 . plusGrand ( var2 )) { System . o u t . p r i n t l n ( " Var1 ␣ e s t ␣ p l u s ␣ g r a n d ␣ que ␣ v a r 2 " ) ; } else { System . o u t . p r i n t l n ( " Var1 ␣ e s t ␣ p l u s ␣ p e t i t ␣ que ␣ v a r 2 " ) ; } } } p u b l i c void a d d E l e m e n t ( Comparable e ) { tab [ nbElements ] = e ; n b E l e m e n t s++ ; } p u b l i c boolean c r o i s s a n t ( ) { f o r ( i n t i = 1 ; i < n b E l e m e n t s ; i ++) { i f ( tab [ i −1]. plusGrand ( tab [ i ] ) ) return false ; } return true ; } Ici les variables var1 et var2 contiennent des références vers des objets dont les classes : I peuvent être différentes I implémentent l’interface Comparable J. Sopena (INRIA/UPMC) } Le polymorphisme en Java. 112 / 121 Outline J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 113 / 121 Choix entre classe et interface : principe Une interface peut servir à faire du polymorphisme comme l’héritage, alors comment choisir entre classe et interface ? L’héritage Polymorphisme et héritage Classes et méthodes abstraites Interfaces Préambule et définition Déclaration et implémentation Polymorphisme d’interface Classe ou interface ? Composition d’interfaces 1. Choix dicté par l’existant : L’héritage n’est plus possible, la classe hérite déjà d’une autre classe. Il ne reste plus que celui l’interface. 2. Choix à la conception : On étudie la relation entre A et B ? I Un objet de classe B "EST UN" A I Un objet de classe B "EST CAPABLE DE FAIRE" A =⇒ Héritage : B extends A. =⇒ Interface : B implements A. J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 114 / 121 Choix entre classe et interface : exemple J. Sopena (INRIA/UPMC) extends Amphibien { implements Amphibie { Le polymorphisme en Java. 116 / 121 Implémentation de plusieurs interfaces extends Batracien implements Amphibie J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 117 / 121 Extension d’une interface Une classe peut hériter d’une autre classe et implémenter une interface : class G r e n o u i l l e ... 115 / 121 L’héritage Polymorphisme et héritage Classes et méthodes abstraites Interfaces Préambule et définition Déclaration et implémentation Polymorphisme d’interface Classe ou interface ? Composition d’interfaces Une grenouille "EST CAPBLE DE FAIRE" amphibie : class G r e n o u i l l e ... } Le polymorphisme en Java. Outline Une grenouille "EST UN" amphibien : class G r e n o u i l l e ... } J. Sopena (INRIA/UPMC) { Lorsqu’une capacité s’exprime comme une extension d’une autre capacité, on peut étendre une interface en utilisant le mot clé extends : } interface SavoirConduire { ... } Une classe peut implémenter plusieurs interfaces : class G r e n o u i l l e ... } J. Sopena (INRIA/UPMC) implements SurTerre, SurEau Le polymorphisme en Java. i n t e r f a c e S a v o i r P i l o t e r extends S a v o i r C o n d u i r e p u b l i c a b s t r a c t void d e r a p e r ( i n t d e g r e ) ; } { 118 / 121 J. Sopena (INRIA/UPMC) Le polymorphisme en Java. { 119 / 121 Composition de plusieurs interfaces Polymorphisme d’interfaces Comme pour les classes, on peut faire du polymorphisme d’interfaces. Lorsqu’une capacité s’exprime comme un ensemble d’autres capacités, on peut faire de la composition d’interfaces en utilisant le mot clé extends : i n t e r f a c e Amphibie extends S u r T e r r e , SurEau ... p u b l i c c l a s s C h a u f f e u r extends Homme implements S a v o i r C o n d u i r e { ... } { p u b l i c c l a s s P i l o t e extends Homme implements S a v o i r P i l o t e r { ... } } public class Course { p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) { SavoirConduire [10] participants ; Attention C h a u f f e u r j u l i e n = new C h a u f f e u r ( ) ; P i l o t e s e b a s t i e n L o e b = new P i l o t e ( ) ; Même si l’on utilise le même mot clé que pour l’héritage, ce n’est pas de l’héritage multiple qui n’existe pas en Java. participants [0] = julien ; participants [1] = sebastienLoeb ; } } J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 120 / 121 J. Sopena (INRIA/UPMC) Le polymorphisme en Java. 121 / 121