Langage Oriente Objet Cours 4
Partie 6 Le polymorphisme
Polymorphisme Le polymorphisme est étroitement associé à l’interaction entre l’héritage et la liaison dynamique Une première forme (simple) : des objets différents peuvent réagir différemment à un même message Par exemple, si on envoie le message dessine à un Rectangle et à un Losange, ces deux objets réagiront chacun à leur manière car ils sont de nature différente.
Polymorphisme Deuxième forme (par l'exemple) : tout polygone sait calculer son périmètre (= somme des longueurs de ses côtés) mise en œuvre par Polygone tout polygone sait calculer la longueur de chacun de ses côtés mise en œuvre par la figure géométrique (Rectangle, Triangle…) un Rectangle et un Triangle sont des Polygone
Polymorphisme On peut définir une variable de type Polygone et lui affecter une instance de Triangle ou de Rectangle (car ce sont des polygones !) Lors d'une demande de calcul du périmètre, la fonction définie au niveau du polygone va faire appel à la fonction de calcul des côtés spécifique au type de polygone (Rectangle ou Triangle)
Polymorphisme Polygone calculePerimetre calculeCote Triangle Polygone surcharge Triangle calculePerimetre
Le polymorphisme class Note { private int value; private Note(int val) { value = val ; } public static final Note middleC = new Note(0), cSharp = new Note(1), cFlat = new Note(2) ; } class Instrument { public void play(Note n) { System.out.println("Instrument.play()"); class Wind extends Instrument { System.out.println("Wind.play()");
Le polymorphisme public class Music { public static void tune(Instrument i) { i.play(Note.middleC); i.play(Note.cFlat ) ; i.play(Note.cSharp ) ; } public static void main(String[] args) { Wind flute = new Wind(); tune(flute); // Upcasting flute est Wind donc flute est un Instrument. La méthode tune a pour but de jouer un morceau de musique (une suite de notes). Quelque soit l’instrument, la suite de notes est la même. Dans la méthode tune, flute est considérée comme un Instrument. Tout Instrument sait jouer une note d’où i.play(…). L’appel à play considère le type réel de l’instrument (ici Wind) et fait donc appel à la fonction play de Wind. Cette « recherche » est effectuée pour toute fonction surchargée.
Final Le mot clé final signifie « changement interdit » Il interdit : la surcharge d’une méthode ( final void f(…) {…} ) la spécialisation d’une classe ( final class A {…} ) la modification d’un attribut ou d’un argument d’une méthode ( final int i )
Final class A { ….. } class B { final int i = 0; // Initialized final final int j ; final A a ; B() { j = 1; // Initialize a = new A(); } B(int x) { j = x; // Initialize a = new A() ; Si les attributs final ne sont pas initialisés lors de leur déclaration, ils doivent alors être initialisés dans le constructeur. Ils ne pourront plus être modifiés par la suite.
Final Les arguments peuvent être aussi déclarés aussi final. Par défaut, les arguments sont passés par valeur ou par référence. Final permet d’interdire toute modification des objets passés en paramètre. class Gizmo { public void spin(){ ….. } public class FinalArguments { void with(final Gizmo g) { g.spin(); } void without(Gizmo g) { g = new Gizmo() ; // OK -- g not final void f(final int i) { i++ ; // Error : Can't change int g(final int i) { return i + 1 ; // OK
La classe Object La classe Object est la plus importante de toutes les classes Java car toute classe Java hérite de Object . La classe Object met diverses méthodes à éventuellement surcharger : Object clone() : crée un clone de l’objet int hashCode() : adresse mémoire où est stockée une instance (utilisé par défaut dans equals…) boolean equals(Object obj) : compare deux objets (à spécialiser) String toString() : retourne une représentation de l’objet sous forme d’une chaîne de caractères final Class getClass() : retourne une référence sur l’objet de type Class caractérisant la classe d’appartenance de l’objet
Clonage d’objets Le clonage d’objets est possible si votre classe hérite de la classe Object (ou si votre classe implémente l’interface Cloneable). Par défaut, la fonction Object clone() est protected et pour la rendre visible, il faut la déclarer public lors de la surcharge. Lors du clonage, aucun constructeur n’est appelé ; une copie bit à bit est réalisée. Dans la surcharge, débuter par un appel à la méthode clone de la classe mère (super) afin de réaliser le clonage de la partie détenue par les classes mères.
Clonage d’objets class MyObject extends Object{ int i; MyObject(int ii) { i = ii; } public Object clone() { Object o = null; o = super.clone(); … return o; public class LocalCopy { static MyObject g(MyObject v) { v.i++; return v; } static MyObject f(MyObject v) { v = (MyObject)v.clone(); public static void main(String[] args) { MyObject a = new MyObject(11); MyObject b = g(a); … MyObject c = new MyObject(47); MyObject d = f(c); }}
L'agrégation L'agrégation est une relation qui permet de décrire un objet composite en terme d'objets qui le constituent Par exemple, une voiture : 1 châssis + 4 roues + 1 moteur ...
Clonage d’objets composés On parle d’objet composé ou de composition d’objets si les attributs de l’objet sont des objets (et non des attributs de type primitif). Le clonage d’un objet composé doit, de manière générale, faire appel à la fonction de clonage de chaque de ses membres.
Clonage d’objets composés class DepthReading extends Object { private double depth ; public DepthReading(double depth) { this.depth = depth; } public Object clone() { Object o = null; o = super.clone(); return o; } class TemperatureReading extends Object { private long time; private double temperature; public TemperatureReading(double temperature) { time = System.currentTimeMillis(); this.temperature = temperature; } public Object clone() { Object o = null; o = super.clone(); return o; }} …/…
Clonage d’objets composés class OceanReading extends Object { private DepthReading depth; private TemperatureReading temperature; public OceanReading(double tdata, double ddata){ temperature = new TemperatureReading(tdata); depth = new DepthReading(ddata); } public Object clone() { OceanReading o = null ; o = (OceanReading)super.clone() ; o.depth = (DepthReading)o.depth.clone() ; o.temperature = (TemperatureReading)o.temperature.clone() ; return o ;
Classe abstraite et interface Partie 7 Classe abstraite et interface
Les classes abstraites Une classe abstraite est une classe ayant au moins une méthode abstraite Une méthode abstraite ne possède pas de définition Une classe abstraite ne peut pas être instanciée ( new ) Une classe dérivée d'une classe abstraite ne redéfinissant pas toutes les méthodes abstraites est elle-même abstraite
Les classes abstraites abstract class Shape { public abstract double perimeter(); } class Circle extends Shape { ... public double perimeter() { return 2 * Math.PI * r ; } class Rectangle extends Shape { public double perimeter() { return 2 * (height + width) ; } Shape[] shapes = { new Circle(2), new Rectangle(2,3), new Circle(5) }; double sum_of_perimeters = 0 ; for(int i=0; i<shapes.length; i++){ sum_of_perimeters = shapes[i].perimeter() ;
Les interfaces Une interface correspond à une classe où toutes les méthodes sont abstraites Une interface est composée de méthodes abstraites et d’attributs statiques et finaux (constantes) Une classe peut implémenter ( implements ) une ou plusieurs interfaces, tout en héritant ( extends ) d'une seule classe Une interface peut hériter ( extends ) de plusieurs interfaces.
Les interfaces abstract class Shape { public abstract double perimeter() ; } interface Drawable { public void draw(); class Circle extends Shape implements Drawable { public double perimeter() { return 2 * Math.PI * r ; } public void draw() { ... } class Rectangle extends Shape implements Drawable, Serializable { ... public double perimeter() { return 2 * (height + width) ; } public void draw() {...} ------------------------------------------------------------------------------------------------------------ Drawable[] drawables = { new Circle(2), new Rectangle(2,3), new Circle(5) } ; for(int i=0; i<drawables.length ; i++){ drawables[i].draw() ;
Les interfaces Un attribut statique peut être une instance d’interface. Création d’une instance de l’interface I class C { … static final I i = new I() { int f() { } }; interface I { int f(); } Implémentation de la fonction abstraite
Partie 8 Les inner classes
Les inner classes Elles permettent de : Déclarer une classe dans un bloc (inner class) Instancier une classe anonyme (anonymous class) Elles affinent la localisation des classes et simplifient le développement Attention : elles peuvent réduire la lisibilité des sources.
Les inner classes public class FixedStack { Object array[] ; int top = 0 ; public void push(Object item) { ... } public Object pop() { ... } public boolean isEmpty() { ... } public java.util.Enumeration element() { return new Enumerator() ; } class Enumerator implements java.util.Enumeration { int count = top; public boolean hasMoreElements() { return count > 0 ; } public Object nextElement() { if (count == 0) throw NoSuchElementException("FixedStack"); return array[--count]; }
Les inner classes Ce qui est produit par le compilateur : public class FixedStack { ... public java.util.Enumeration element() { return new FixedStack$Enumerator(this) ; } } class FixedStack$Enumerator implements java.util.Enumeration { private FixedStack this$0; FixedStack$Enumerator(FixedStack this$0) { this.this$0 = this$0; this.count = this$0.top; int count; public boolean hasMoreElements() { return count > 0; } public Object nextElement() { if (count == 0) throw NoSuchElementExceptio("FixedStack"); return this$0.array[--count];
Les inner classes Exemple de classe locale : ... Enumeration myEnumeration(final Object array[]) { class E implements java.util.Enumeration { int count = top ; public boolean hasMoreElements() { return count > 0 ; } public Object nextElement() { if (count == 0) throw NoSuchElementExceptio("FixedStack"); return array[--count]; } return new E(); ….
Les inner classes Exemple de classe anonyme : ... Enumeration myEnumeration(final Object array[]) { return new java.util.Enumeration() { int count = 0 ; public boolean hasMoreElements() { return count < array.length ; } public Object nextElement() { return array[count++]; …
Les inner classes Ce qui est produit par le compilateur : Enumeration myEnumeration(final Object array[]) { return new MyOuterClass$19(array); } ... class MyOuterClass$19 implements java.util.Enumeration { private Object val$array ; int count ; MyOuterClass$19(Object val$array) { this.val$array = val$array ; count = 0; public boolean hasMoreElements() { return count < val$array.length ; } public Object nextElement() { return val$array[count++];