12/04/2017 8 Le polymorphisme Cours 8 Cours 8
Plan du cours 8 Polymorphisme Le problème 12/04/2017 Plan du cours 8 Polymorphisme Le problème Règle : affectation de références Rappel de la transmission de para Résolution d'un appel de méthode Cas de la redéfinition Cas de la surcharge Cours 8 Cours 8
Polymorphisme Étymologiquement : plusieurs formes. 12/04/2017 Polymorphisme Étymologiquement : plusieurs formes. En pratique : le polymorphisme donne la possibilité d’appliquer à des listes d’objets apparentés une action portant le même nom, par exemple afficher(). L’action déclenchée est cependant spécifique à chacun de ces objets. La méthode d’affichage est propre à l’objet. Le mécanisme trouve dynamiquement la bonne méthode pour l’objet concerné. Cours 8 Cours 8
12/04/2017 Le problème Soit p un handle sur un objet de type Point défini comme suit : Point p = new Point(“P", 10, 20) Quelles méthodes sont accessibles avec le handle p? Point String nom CHAMPS int x int y METHODES Point(String nom, int x, int y) void déplacer(int nouveauX, int nouveau y) void déplacer(Point nouveau) SURCHARGE void afficher() On reprend l’exemple sans la privatisation pour simplifier les diapos. Pas de problème, ce sont les méthodes déplacer et afficher de sa classe. Cours 8 Cours 8
PointColoré hérite de Point 12/04/2017 Soit maintenant une classe PointColoré qui hérite de Point. Et un PointColoré pc = new PointColoré("PC",100, 200, Color.yellow)) Quelles méthodes puis-je utiliser avec pc ? PointColoré hérite de Point Color couleur CHAMP METHODES PointColoré(String nom, int x, int y, Color couleur) void afficher() REDEFINITION La méthode afficher() de PointColoré comme ceci : pc.afficher(). Mais aussi toutes les méthodes non privées de Point dont hérite PointColoré. Par exemple : pc.déplacer(300, 400). Cours 8 Cours 8
PointColoré hérite de Point 12/04/2017 Point String nom CHAMPS int x int y METHODES Point(String nom, int x, int y) void déplacer(int nouveauX, int nouveau y) void déplacer(Point nouveau) SURCHARGE void afficher() PointColoré hérite de Point Color couleur CHAMP METHODES PointColoré(String nom, int x, int y, Color couleur) void afficher() REDEFINITION Point p = new Point(“P", 10, 20); PointColoré pc; pc=new PointColoré("PC",100,200,Color.yellow)); pc.déplacer(1000, 2000); Point poly; poly.déplacer(300, 400); Et un PointColoré pc=new PointColoré("PC",100,200,Color.yellow)) Quelles méthodes puis-je utiliser avec pc ? La méthode afficher de PointColoré comme ceci : pc.afficher(). Mais aussi toutes les méthodes public ou protected de Point dont hérite PointColoré. Par exemple : pc.déplacer(300, 400) Définissons maintenant un handle poly de type Point : Point poly. Si l’on fait l’affectation : poly = p ; puis poly.déplacer(1000, 2000). poly apparaît comme un autre nom pour désigne l’objet créé avec p. C’est un alias. C’est l’objet de nom p qui est déplacé. Si l’on fait poly.afficher(), c’est la méthode afficher de Point qui est utilisée. A t’on le droit de faire l’affecation : poly = pc ? autrement dit : référenceAncêtre = référenceDescendant OUI. Alors, si l’on fait poly.afficher(), quelle sera la méthode afficher() utilisée. Celle de Point ou celle de PointColoré ? Ce sera la méthode afficher()de PointColoré. C’est-à-dire la méthode de l’objet effectivement désigné par pc. poly = p; poly.déplacer(1000, 2000); alias poly.afficher(); poly = pc; ?????? poly.afficher(); Quelle méthode ??????? Cours 8 Cours 8
référenceAncêtre = référenceDescendant 12/04/2017 A t’on le droit de faire l’affectation : poly = pc ? autrement dit : référenceAncêtre = référenceDescendant OUI. Alors, si l’on fait poly.afficher(), quelle sera la méthode afficher() utilisée : Celle de Point ou celle de PointColoré ? Ce sera la méthode afficher() de PointColoré. C’est-à-dire la méthode de l’objet effectivement désigné par pc. Cours 8 Cours 8
12/04/2017 Le polymorphisme permet alors à un handle de faire référence, au moment de l'exécution, à des instances de différentes classes issues d'une même lignée. C'est cette caractéristique qui donne toute sa puissance à la redéfinition. Ainsi, la liaison entre le handle et la méthode est réalisée au moment de l'exécution et non pas comme dans les langages habituels au moment de la compilation. On parle de liaison dynamique ou liaison retardée (late binding). Dans la pratique, cela se traduit par la possibilité d'appeler plusieurs méthodes du même nom. Ex : la surcharge ou la redéfinition. Cours 8 Cours 8
Règle : affectation de références 12/04/2017 Règle : affectation de références référenceAncêtre = référenceDescendant L'inverse est interdit. Mais un cast est possible. Dans ce cas il y aura contrôle de lignée à l'exécution. Du polymorphisme se déduit la possibilité d'affecter une référence sur un descendant à une référence d'un type ancêtre. Ce qui peut être compris comme : chaque objet d'une sous-classe est aussi un objet de la super classe mais avec des propriétés spéciales. Est donc admis par le compilateur : référenceAncêtre = référenceDescendant Cours 8 Cours 8
Rappel de la transmission de para : copie de valeurs 12/04/2017 Rappel de la transmission de para : copie de valeurs Règle de compatibilité au sens de l’affectation. Cours 8 Cours 8
Résolution d'un appel de méthode 12/04/2017 Résolution d'un appel de méthode Quelle sera la méthode appelée ? Cas de la redéfinition late binding Cas de la surcharge Cours 8 Cours 8
12/04/2017 Cas de la redéfinition Dans l'appel maRéférence.méthode(…), la résolution se fait en deux temps. Lors de la compilation, le compilateur examine le type du handle maRéférence et examine si, dans cette classe, il peut trouver une méthode (présente ou héritée) ayant une signature compatible (compatibilité au sens de l’affectation entre paramètres effectifs et formels). La liaison n’est pas encore figée. A l'exécution, s'il y a redéfinition, le choix de la méthode appelée dépend du type de l'objet effectivement pointé par maRéférence. La méthode appelée ne dépend pas de la classe du handle maRéférence mais est recherchée dans la classe de l'objet effectivement pointé par maRéférence. Dans une classe dérivée, une méthode a même nom et même signature qu’une méthode d’une classe ancêtre Dans l'appel maRéférence.méthode(…), la résolution se fait en deux temps. Lors de la compilation, le compilateur examine le type du handle maRéférence et examine si, dans cette classe, il peut trouver une méthode (présente ou héritée) ayant une signature compatible (compatibilité au sens de l’affectation entre paramètres effectifs et formels). La liaison n’est pas encore figée. A l'exécution, s'il y a redéfinition, le choix de la méthode appelée dépend du type de l'objet effectivement pointé par maRéférence. La méthode appelée ne dépend pas de la classe du handle maRéférence mais est recherchée dans la classe de l'objet effectivement pointé par maRéférence. Point p = new Point("P", 100, 200) ; p.afficher() ; // Méthode de Point appelée PointColoré pc = new PointColoré("PC", 10, 20); pc.afficher(); // Méthode de PointColoré appelée // Application du polymorphisme p = pc; // Ref ancêtre = ref descendant p.afficher(); // Méthode de PointColoré appelée *** p.déplacer(pc); // Méthode de Point, on lui transmet un point coloré *** L'objet effectivement pointé par p est de type PointColoré. Autrement dit, le choix de la méthode appelée se fait au moment de l'exécution : late binding. Cours 8 Cours 8
Cas de la redéfinition : exemple 12/04/2017 Cas de la redéfinition : exemple Point p = new Point("P", 100, 200) ; p.afficher() ; // Méthode de Point appelée PointColoré pc = new PointColoré("PC", 10, 20); pc.afficher(); // Méthode de PointColoré appelée // Application du polymorphisme p = pc; // Ref ancêtre = ref descendant p.afficher(); // Méthode de PointColoré appelée *** p.déplacer(pc); // Méthode de Point, on lui transmet un point coloré *** L'objet effectivement pointé par p est de type PointColoré. Autrement dit, le choix de la méthode appelée se fait au moment de l'exécution : late binding. Cours 8 Cours 8
12/04/2017 Cas de la surcharge Compatibilité des paramètres effectifs et formels (au sens de l’affectation). Les paramètres sont transmis par valeur (copie de la valeur). Cela vaut aussi pour les handles. Il y a donc compatibilité de paramètres lorsque une référence sur un descendant est transmise à un paramètre formel référence sur un ancêtre. Dans une même classe ou dans une classe dérivée, deux méthodes ont même nom et des signatures différentes. Compatibilité des paramètres effectifs et formels au sens de l’affectation. Les paramètres sont transmis par valeur (copie de la valeur). Cela vaut aussi pour les handles. Il y a donc compatibilité de paramètres lorsque une référence sur un descendant est transmise à un paramètre formel référence sur un ancêtre. Lorsque plusieurs méthodes possèdent des paramètres compatibles avec ceux de l'appel, Java choisit la méthode la plus spécifique, c'est-à-dire la plus basse dans la lignée hiérarchique. On peut rencontrer des méthodes compatibles de même niveau hiérarchique. L'appel est alors ambigu. L'appel ne pouvant être résolu par le compilateur, il est déclaré invalide. Ces cas ne seront pas étudiés ici. Cf. Le langage Java Ken Arnold et James Gosling, Thomson Publishing p114. Cours 8 Cours 8