Pour aller plus loin : idiomes - Télécom SudParis · 2020. 11. 13. · Pour aller plus loin :...

30
Pour aller plus loin : idiomes Denis Conan avec Christian Bac Revision : 4682 CSC4102 Télécom SudParis Janvier 2021

Transcript of Pour aller plus loin : idiomes - Télécom SudParis · 2020. 11. 13. · Pour aller plus loin :...

  • Pour aller plus loin : idiomes

    Denis Conan

    avec Christian Bac

    Revision : 4682

    CSC4102

    Télécom SudParis Janvier 2021

  • Pour aller plus loin : idiomes

    Table des matières

    Pour aller plus loin : idiomesDenis Conan, avec Christian Bac, Télécom SudParis, CSC4102Janvier 2021 1

    Sommaire 3

    1 Création et destruction d’objets 41.1 Intérêt des méthodes de classes pour la création . . . . . . . . . . . . . . . . . . . . . . . . . . . 51.2 Problème du constructeur dépendant d’une méthode rédéfinie . . . . . . . . . . . . . . . . . . . 61.3 Création d’objet avec beaucoup d’attributs, certains optionnels . . . . . . . . . . . . . . . . . . 71.4 Non-instanciabilité d’une classe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81.5 Éviter la création inutile d’objet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91.6 Éviter le concept de finalizer des classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

    2 Idiomes JAVA, exemples, méthodes de la classe Object communes à tous les objets 112.1 Méthode equals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

    2.1.1 Exemple d’erreur sur la propriété de symétrie . . . . . . . . . . . . . . . . . . . . . . . . 132.1.2 Exemple d’erreur sur la propriété de transitivité . . . . . . . . . . . . . . . . . . . . . . 142.1.3 Leçons à retenir suite à l’étude des 2 exemples précédents . . . . . . . . . . . . . . . . . 152.1.4 Tests des propriétés de equals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

    2.2 Clonage d’objet, méthode clone . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172.2.1 Concept du clonage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182.2.2 Diagramme de classes exemple pour présenter le clonage . . . . . . . . . . . . . . . . . . 192.2.3 Représentation graphique d’une copie légère . . . . . . . . . . . . . . . . . . . . . . . . . 202.2.4 Représentation graphique d’une copie plus profonde . . . . . . . . . . . . . . . . . . . . 222.2.5 Représentation graphique d’une copie profonde . . . . . . . . . . . . . . . . . . . . . . . 24

    3 Classes immuables/inaltérables 273.1 Cas des collections immuables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

    Bibliographie 30

    Télécom SudParis — Denis Conan — Janvier 2021 — CSC4102 2

  • Pour aller plus loin : idiomes

    # 2

    '

    &

    $

    %

    Sommaire

    1 Création et destruction d’objets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 Idiomes JAVA, exemples, méthodes de la classe Object communes à tous les objets103 Classes immuables/inaltérables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

    Dans les sections qui suivent, nous parcourons un ensemble de bonnes façons de programmer, c’est-à-dire idiomes, en JAVA. La plupart des éléments sont extraits du livre de référence de l’un des membres del’équipe de conception du langage JAVA : J. Bloch, « JAVA efficace », 2nd Edition, 2008. Nous ne pouvonsque conseiller la lecture de cet ouvrage. Nous insérons ici des éléments directement en lien avec le moduleCSC4102.

    Une différence importante entre l’étude que nous proposons dans ces quelques pages et le livre de J.Blochse situe entre le fait que nous concevons une application et le fait que le livre discute aussi de la conception debibliothèques : par exemple, J. Bloch est un des principaux contributeurs de la bibliothèque des collectionsJAVA. Dans la conception d’une bibliothèque, la programmation doit faciliter les évolutions futures de labibliothèque ainsi que l’extension par des tiers de la bibliothèque. Ces compétences ne sont clairement pasdans le périmètre du module CSC4102.

    Nous commençons par étudier la création et la destruction d’objets. Puis, nous revenons sur les certainesdes méthodes communes à tous les objets.

    Télécom SudParis — Denis Conan — Janvier 2021 — CSC4102 3

  • Pour aller plus loin : idiomes

    # 3

    '

    &

    $

    %

    1 Création et destruction d’objets

    1.1 Intérêt des méthodes de classes pour la création . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41.2 Problème du constructeur dépendant d’une méthode rédéfinie . . . . . . . . . . . . . . . . . . . 51.3 Création d’objet avec beaucoup d’attributs, certains optionnels . . . . . . . . . . . . . . . . . . 61.4 Non-instanciabilité d’une classe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71.5 Éviter la création inutile d’objet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81.6 Éviter le concept de finalizer des classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

    Dans cette section, nous présentons quelques idiomes très utilisés dans la conception de bibliothèque. Laconception de bibliothèque met en œuvre des idiomes plus complexes ou plus subtiles.

    Télécom SudParis — Denis Conan — Janvier 2021 — CSC4102 4

  • Pour aller plus loin : idiomes 1 Création et destruction d’objets

    # 4

    '

    &

    $

    %

    1.1 Intérêt des méthodes de classes pour la création

    ■ Repris de l’Item 1 de [Bloch, 2008]

    ■ Intérêts des méthodes de classes :♦ Nom, plutôt que new : p.ex. Boolean.valueOf♦ Peut ne pas créer un nouvel objet, mais retourner la référence d’une instance

    existante : p.ex. gestion d’un cache♦ Peut retourner un objet d’une classe enfant : p.ex. la classe Collections

    contient plusieurs dizaines de méthodes de classes pour construire tous les typesde collections▶ Collections.singletonList(o) retourne une liste non modifiable

    contenant uniquement o♦ Permet des constructions moins verbeuses : p.ex. pour les classes paramétrées▶ HashMap dictionnaire = newInstance();

    Exemple de méthode classe dans la bibliothèque des collections :Classe seance7.creationdestructiondesobjets.CreationParMethodeDeClasse

    1 public class CreationParMethodeDeClasse {2 @SuppressWarnings("unused") // pour eviter le warning dans Eclipse3 public static void main(String [] args) {4 List l = Collections.singletonList("un");5 System.out.println("l␣instanceof␣List␣=␣" + (l instanceof List)6 + "\nl␣de␣type␣\"" + l.getClass () + "\"");7 // construction moins verbeuse : d2 moins verbeux que d18 HashMap d1 = new HashMap ();9 HashMap d2 = newInstance ();

    10 }11 private static HashMap newInstance () {12 return new HashMap ();13 }14 }

    Résultat de l’exécution :

    l instanceof List = truel de type "class java.util.Collections$SingletonList"

    Télécom SudParis — Denis Conan — Janvier 2021 — CSC4102 5

  • Pour aller plus loin : idiomes 1 Création et destruction d’objets

    # 5

    '

    &

    $

    %

    1.2 Problème du constructeur dépendant d’une méthoderédéfinie

    ■ Repris de l’Item 17 de [Bloch, 2008]

    ■ Concevoir une classe qui peut être étendue♦ Un constructeur ne doit pas appeler une autre méthode de la classe si cette

    méthode peut être redéfinie▶ Sous risque de surprise

    Classe seance7.creationdestructiondesobjets.ParentConstructeurDependantMethodeRedefinie

    1 public class ParentConstructeurDependantMethodeRedefinie {2 public ParentConstructeurDependantMethodeRedefinie () { methodeRedefinie (); }3 public void methodeRedefinie () { } }

    Classe seance7.creationdestructiondesobjets.EnfantConstructeurDependantMethodeRedefinie

    1 public class EnfantConstructeurDependantMethodeRedefinie2 extends ParentConstructeurDependantMethodeRedefinie {3 public EnfantConstructeurDependantMethodeRedefinie () { super (); }4 @Override public void methodeRedefinie () { System.out.println("surprise"); } }

    Voici un exemple d’utilisation qui suprendra le programmeur qui a étendu la classesParentConstructeurDependantMethodeRedefinie.

    Classe seance7.creationdestructiondesobjets.ExempleConstructeurDependantMethodeRedefinie

    1 package eu.telecomsudparis.csc4102.cours.seance7.creationdestructiondesobjets;23 public class ExempleConstructeurDependantMethodeRedefinie {4 public static void main(String [] args) {5 new ParentConstructeurDependantMethodeRedefinie ();6 new EnfantConstructeurDependantMethodeRedefinie ();7 }8 }

    Télécom SudParis — Denis Conan — Janvier 2021 — CSC4102 6

  • Pour aller plus loin : idiomes 1 Création et destruction d’objets

    # 6

    '

    &

    $

    %

    1.3 Création d’objet avec beaucoup d’attributs, certainsoptionnels

    ■ Repris de l’Item 2 de [Bloch, 2008]

    ■ Nous aimons dans des langages comme Python écriredef ClasseAvecBeaucoupDAttributs(a, b=1.0, c="valeurpardefaut"): ...

    ClasseAvecBeaucoupDAttributs(1)ClasseAvecBeaucoupDAttributs(1, 2.0)ClasseAvecBeaucoupDAttributs(1, b=2.0)

    ■ Utilisation de l’idiome « Builder »♦ Il simule les paramètres optionnels

    Classe seance6.creationdestructiondesobjets.ClasseAvecBeaucoupDAttributs

    1 public class ClasseAvecBeaucoupDAttributs {2 private int a;3 private double b = 1.0;4 private String c = "valeur␣par␣defaut";5 public ClasseAvecBeaucoupDAttributs(final int a) {6 this.a = a;7 }8 public ClasseAvecBeaucoupDAttributs b(final double b) {9 this.b = b;

    10 return this;11 }12 public ClasseAvecBeaucoupDAttributs c(final String c) {13 this.c = c;14 return this;15 }16 @Override17 public String toString () {18 return "ClasseAvecBeaucoupDAttributs␣[a=" + a + ",␣b=" + b + ",␣c=" + c19 + "]";20 }21 }

    Classe seance6.creationdestructiondesobjets.CreationAvecIdiomeBuilder

    1 public class CreationAvecIdiomeBuilder {2 public static void main(String [] args) {3 ClasseAvecBeaucoupDAttributs o = (new ClasseAvecBeaucoupDAttributs (1))4 .b(2.0).c("autre");5 System.out.println(o);6 }7 }

    Résultat de l’exécution :

    ClasseAvecBeaucoupDAttributs [a=1, b=2.0, c=autre]

    Télécom SudParis — Denis Conan — Janvier 2021 — CSC4102 7

  • Pour aller plus loin : idiomes 1 Création et destruction d’objets

    # 7

    '

    &

    $

    %

    1.4 Non-instanciabilité d’une classe

    ■ Repris de l’Item 4 de [Bloch, 2008]

    ■ Laisser la classe concrète et mettre le constructeur par défaut privéClasse seance6.creationdestructiondesobjets.ClasseNonInstanciable

    1 public class ClasseNonInstanciable {2 private ClasseNonInstanciable () {3 throw new AssertionError ();4 }5 }

    ■ Contrainte gardée dans les classes enfantspublic class ClasseEnfantNonInstanciable extends ClasseNonInstanciable {

    private ClasseEnfantNonInstanciable(final String a) {...}

    }

    ♦ Donne le message d’erreur suivant à la compilation :▶ Implicit super constructor ClasseNonInstanciable() is not visible. Must

    explicitly invoke another constructor

    Télécom SudParis — Denis Conan — Janvier 2021 — CSC4102 8

  • Pour aller plus loin : idiomes 1 Création et destruction d’objets

    # 8

    '

    &

    $

    %

    1.5 Éviter la création inutile d’objet

    ■ Repris de l’Item 5 de [Bloch, 2008]

    ■ Les classes de base proposent souvent des méthodes de classe ou des moyens pourréutiliser des objets créés plutôt que d’en instancier de nouveaux♦ P.ex. la classe String : « A string literal always refers to the same instance of

    class String. This is because string literals —or, more generally, strings that arethe values of constant expressions— are “interned” so as to share uniqueinstances, using the method String.intern » [Gosling et al., 2015, page 36]

    Classe seance6.creationdestructiondesobjets.EviterLaCreationInutileDObjet

    1 for (int i = 0; i < 1000000000; i++) {2 s = new String("un");3 }4 for (int i = 0; i < 1000000000; i++) {5 s = "un";6 }

    ■ Résultat sur ma machine : 33ms contre 2ms

    Télécom SudParis — Denis Conan — Janvier 2021 — CSC4102 9

  • Pour aller plus loin : idiomes 1 Création et destruction d’objets

    # 9

    '

    &

    $

    %

    1.6 Éviter le concept de finalizer des classes

    ■ Repris de l’Item 7 de [Bloch, 2008]

    ■ « If an object declares a finalizer, the finalizer is executed before the object isreclaimed to give the object a last chance to clean up resources that would nototherwise be released » [Gosling et al., 2015, page 4]

    ■ Mais :♦ « The Java Virtual Machine may eventually automatically invoke its

    finalizer » [Gosling et al., 2015, page 375]▶ Donc, aucune garantie que la méthode finalize soit appelée⋆ Par conséquent, ne pas mettre de code important dans un finalizer

    Classe seance6.creationdestructiondesobjets.ClasseAvecFinalizer

    1 public class ClasseAvecFinalizer {2 private int a;3 public ClasseAvecFinalizer(final int a) {4 this.a = a;5 }6 @Override7 public void finalize () {8 System.out.println("execution␣finalize␣de␣" + this);9 }

    10 @Override11 public String toString () {12 return "ClasseAvecFinalizer␣[a=" + a + "]";13 }14 }

    Classe seance6.creationdestructiondesobjets.ExempleClasseAvecFinalize

    1 public class ExempleClasseAvecFinalize {2 @SuppressWarnings("unused")3 public static void main(String [] args) {4 ClasseAvecFinalizer o = new ClasseAvecFinalizer (1);5 }6 }

    L’exécution dans mon Eclipse ne donne aucun affichage.

    Télécom SudParis — Denis Conan — Janvier 2021 — CSC4102 10

  • Pour aller plus loin : idiomes

    # 10

    '

    &

    $

    %

    2 Idiomes JAVA, exemples, méthodes de la classe Objectcommunes à tous les objets

    2.1 Méthode equals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112.2 Clonage d’objet, méthode clone . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

    Nous commençons par revenir sur la méthode equals en donnant cette fois-ci des exemples de program-mation de la méthode qui ne respectent pas les propriétés de symétrie et de transitivité ; ces exemples sontnon triviaux mais importants : nous pensons que vous pouvez les comprendre aujourd’hui. Ensuite, nousintroduisons une interface très utilisée pour cloner des objets, avec les concepts importants de copie légèreet copie profonde.

    Télécom SudParis — Denis Conan — Janvier 2021 — CSC4102 11

  • Pour aller plus loin : idiomes Idiomes JAVA, exemples, méthodes de la classe Object

    # 11

    '

    &

    $

    %

    2.1 Méthode equals

    ■ Repris de l’Item 8 de [Bloch, 2008]

    ■ Contrat de la méthode equals [Class Object, JSE8]♦ Prend en argument un Object : utiliser @Override pour éviter une erreur♦ Reflexive : for any non-null reference value x, x.equals(x) should return true♦ Symmetric : for any non-null reference values x and y, x.equals(y) should

    return true if and only if y.equals(x) returns true♦ Transitive : for any non-null reference values x, y, and z, if x.equals(y) returns

    true and y.equals(z) returns true, then x.equals(z) should return true♦ Consistent : for any non-null reference values x and y, multiple invocations of

    x.equals(y) consistently return true or consistently return false, provided noinformation used in equals comparisons on the objects is modified

    ♦ For any non-null reference value x, x.equals(null) should return false

    Dans les diapositives qui suivent, nous jouons aux plus malins en ne nous aidant pas de la générationdes méthodes equals et hashCode avec notre IDE, mais en les programmant nous-même, et de manièreoriginale. Nous tombons alors dans des erreurs.

    Télécom SudParis — Denis Conan — Janvier 2021 — CSC4102 12

  • Idiomes JAVA, exemples, méthodes de la classe Object 2.1 Méthode equals

    # 12

    '

    &

    $

    %

    2.1.1 Exemple d’erreur sur la propriété de symétrieClasse seance7.methodescommunesatouslesobjets.EqualsErreurSymetrie

    1 public EqualsErreurSymetrie(final String s) { this.s = s; }2 @Override public boolean equals(Object obj) {3 if (this == obj) return true; if (obj == null) return false;4 EqualsErreurSymetrie other = (EqualsErreurSymetrie) obj;5 if (s == null) { if (other.s != null) return false; }6 else if (!s.equalsIgnoreCase(other.s)) return false; return true; } }

    Classe seance7.methodescommunesatouslesobjets.EqualsErreurSymetrieEnfant

    1 public EqualsErreurSymetrieEnfant(final String s) { super(s); }2 @Override public boolean equals(Object obj) {3 if (this == obj) return true; if (obj == null) return false;4 EqualsErreurSymetrie other = (EqualsErreurSymetrie) obj;5 if (s == null) { if (other.s != null) return false; }6 else if (!s.equals(other.s)) return false; return true; } }

    Classe seance7.methodescommunesatouslesobjets.ExemplesMethodeEqualsErreurSymetrie

    1 EqualsErreurSymetrie o1 = new EqualsErreurSymetrie("Avec");2 EqualsErreurSymetrieEnfant o2 = new EqualsErreurSymetrieEnfant("avec");3 List l = new ArrayList (); l.add(o1);4 System.out.println(o2.equals(o1) + ",␣" + o1.equals(o2) + ",␣"+ l.contains(o2));

    Le résultat de l’exécution est « false, true, false ».Voici les codes complets.

    Classe seance7.methodescommunesatouslesobjets.EqualsErreurSymetrie

    1 package eu.telecomsudparis.csc4102.cours.seance7.methodescommunesatouslesobjets;23 public class EqualsErreurSymetrie {4 String s;5 public EqualsErreurSymetrie(final String s) { this.s = s; }6 @Override public boolean equals(Object obj) {7 if (this == obj) return true; if (obj == null) return false;8 EqualsErreurSymetrie other = (EqualsErreurSymetrie) obj;9 if (s == null) { if (other.s != null) return false; }

    10 else if (!s.equalsIgnoreCase(other.s)) return false; return true; } }

    Classe seance7.methodescommunesatouslesobjets.ExemplesMethodeEqualsErreurSymetrie

    1 package eu.telecomsudparis.csc4102.cours.seance7.methodescommunesatouslesobjets;23 import java.util.ArrayList;4 import java.util.List;56 public class ExemplesMethodeEqualsErreurSymetrie {7 public static void main(String [] args) {8 EqualsErreurSymetrie o1 = new EqualsErreurSymetrie("Avec");9 EqualsErreurSymetrieEnfant o2 = new EqualsErreurSymetrieEnfant("avec");

    10 List l = new ArrayList (); l.add(o1);11 System.out.println(o2.equals(o1) + ",␣" + o1.equals(o2) + ",␣"+ l.contains(o2));12 }13 }

    La méthode EqualsErreurSymetrie::equals utilise la méthode String::equalsIgnoreCase alorsque la méthode redéfinie dans la classe enfant EqualsErreurSymetrieEnfant utilise la méthodeString::equals. Aussi, « o2.equals(o1) » utilise la méthode EqualsErreurSymetrieEnfant::equals,donc String::equals, et est évalué à « false ». Ensuite, « o1.equals(o2) » utilise la méthodeEqualsErreurSymetrie::equals, donc String::equalsIgnoreCase, et est évaluée à « true ». Enfin,« l.contains(o2) » utilise la méthode EqualsErreurSymetrieEnfant::equals, donc String::equals,et est évalué à « false ».

    Télécom SudParis — Denis Conan — Janvier 2021 — CSC4102 13

  • Idiomes JAVA, exemples, méthodes de la classe Object 2.1 Méthode equals

    # 13

    '

    &

    $

    %

    2.1.2 Exemple d’erreur sur la propriété de transitivitéClasse seance7.methodescommunesatouslesobjets.Parent

    1 public class Parent { private int a; // ...

    Classe seance7.methodescommunesatouslesobjets.EqualsErreurTransitivite

    1 public class EqualsErreurTransitivite extends Parent {2 private int b;3 public EqualsErreurTransitivite(final int a, final int b) {super(a);this.b = b;}4 @Override public boolean equals(Object obj) {5 if (this == obj) return true; if (obj == null) return false;6 if (obj.getClass ().equals(Parent.class)) return super.equals(obj);7 EqualsErreurTransitivite other = (EqualsErreurTransitivite) obj;8 return super.equals(other) && b == other.b; } }

    Classe seance7.methodescommunesatouslesobjets.ExemplesMethodeEqualsErreurTransitivite

    1 Parent p = new Parent (1);2 EqualsErreurTransitivite e1 = new EqualsErreurTransitivite (1, 2);3 EqualsErreurTransitivite e2 = new EqualsErreurTransitivite (1, 3);4 System.out.println(e1.equals(p) + ",␣" + p.equals(e2) + ",␣" + e1.equals(e2));5 }

    ■ Résultat de l’exécution : true, true, false

    Le résultat de l’exécution est « true, true, false ».Voici les codes complets.

    Classe seance7.methodescommunesatouslesobjets.Parent

    1 package eu.telecomsudparis.csc4102.cours.seance7.methodescommunesatouslesobjets;23 public class Parent { private int a; // ...4 public Parent(final int a) { this.a = a;}5 @Override public boolean equals(Object obj) {6 if (this == obj) return true;7 if (obj == null) return false;8 if (!(obj instanceof Parent)) return false;9 Parent other = (Parent) obj;

    10 if (a != other.a) return false;11 return true; } }

    Classe seance7.methodescommunesatouslesobjets.EqualsErreurTransitivite

    1 package eu.telecomsudparis.csc4102.cours.seance7.methodescommunesatouslesobjets;23 public class EqualsErreurTransitivite extends Parent {4 private int b;5 public EqualsErreurTransitivite(final int a, final int b) {super(a);this.b = b;}6 @Override public boolean equals(Object obj) {7 if (this == obj) return true; if (obj == null) return false;8 if (obj.getClass ().equals(Parent.class)) return super.equals(obj);9 EqualsErreurTransitivite other = (EqualsErreurTransitivite) obj;

    10 return super.equals(other) && b == other.b; } }

    Classe seance7.methodescommunesatouslesobjets.ExemplesMethodeEqualsErreurTransitivite

    1 package eu.telecomsudparis.csc4102.cours.seance7.methodescommunesatouslesobjets;23 public class ExemplesMethodeEqualsErreurTransitivite {4 public static void main(String [] args) {5 Parent p = new Parent (1);6 EqualsErreurTransitivite e1 = new EqualsErreurTransitivite (1, 2);7 EqualsErreurTransitivite e2 = new EqualsErreurTransitivite (1, 3);8 System.out.println(e1.equals(p) + ",␣" + p.equals(e2) + ",␣" + e1.equals(e2));9 }

    10 }

    La classe EqualsErreurTransitivite étend la classe Parent et ajoute l’attribut « b » à l’attribut« a ». La méthode EqualsErreurTransitivite::equals se limite à la comparaison de l’attribut « a » sil’argument est un objet de type Parent, et compare les attributs « a » et « b » sinon. Si l’idée peut paraîtreséduisante de prime abord, l’exemple montre trivialement que la transitivité n’est pas respectée.

    Télécom SudParis — Denis Conan — Janvier 2021 — CSC4102 14

  • Idiomes JAVA, exemples, méthodes de la classe Object 2.1 Méthode equals

    # 14

    '

    &

    $

    %

    2.1.3 Leçons à retenir suite à l’étude des 2 exemples précédents■ Utiliser la génération Eclipse

    ♦ Pose de l’annotation @Override♦ Évite l’utilisation de plusieurs transtypages (comme dans les exemples montrés

    ci-avant)

    ■ Faire attention aux attributs pris en compte dans equals et qui changent de valeur♦ Commencer par les éviter♦ En cas de changement, que deviennent les collections les contenant ?▶ Étudier l’interaction avec hashCode (cf. diapositives à venir)

    ■ Faire attention à la redéfinition dans les classes enfants♦ Si collection « sur la totalité de l’arbre d’héritage » alors commencer par redéfinir

    equals dans la classe parente sans redéfinition dans les classes enfantset utiliser l’opérateur instanceof au lieu de la méthode getClass

    ■ Dans le cas exceptionnel et vraiment déconseillé où vous décidiez d’écrirevous-mêmes vos méthodes equals et hashCodefaites des vérifications dans votre projet (Cf. diapositive qui suit)

    Télécom SudParis — Denis Conan — Janvier 2021 — CSC4102 15

  • Idiomes JAVA, exemples, méthodes de la classe Object 2.1 Méthode equals

    # 15

    '

    &

    $

    %

    2.1.4 Tests des propriétés de equalsClasse seance7.methodescommunesatouslesobjets.Parent

    1 public class Parent { private int a; // ...

    Classe seance7.methodescommunesatouslesobjets.Enfant

    1 public class Enfant extends Parent { private int b;2 public Enfant(final int a, final int b) { super(a);this.b = b;} }

    Classe seance7.methodescommunesatouslesobjets.TestEquals

    1 public class TestEquals {2 private Parent p; private Enfant e, e2;3 @Before public void setUp() throws Exception {4 p = new Parent (1); e = new Enfant(1, 2); e2 = new Enfant (1,2); }5 @After public void tearDown () throws Exception {6 p = null; e = null; e2 = null; }7 @Test public void testReflexivite () {8 Assert.assertTrue(p.equals(p) && e.equals(e) && e2.equals(e2)); }9 @Test public void testSymetrie () {

    10 Assert.assertTrue ((!p.equals(e)||e.equals(p))&&(!e.equals(p)||p.equals(e))); }11 @Test public void testTransitivity () {12 Assert.assertTrue(e2.equals(p) && p.equals(e) && e2.equals(e)); } }

    Voici les codes complets.Classe seance7.methodescommunesatouslesobjets.Parent

    1 package eu.telecomsudparis.csc4102.cours.seance7.methodescommunesatouslesobjets;23 public class Parent { private int a; // ...4 public Parent(final int a) { this.a = a;}5 @Override public boolean equals(Object obj) {6 if (this == obj) return true;7 if (obj == null) return false;8 if (!(obj instanceof Parent)) return false;9 Parent other = (Parent) obj;

    10 if (a != other.a) return false;11 return true; } }

    Classe seance7.methodescommunesatouslesobjets.Enfant

    1 package eu.telecomsudparis.csc4102.cours.seance7.methodescommunesatouslesobjets;23 @SuppressWarnings("unused")4 public class Enfant extends Parent { private int b;5 public Enfant(final int a, final int b) { super(a);this.b = b;} }

    Classe seance7.methodescommunesatouslesobjets.TestEquals

    1 package eu.telecomsudparis.csc4102.cours.seance7.methodescommunesatouslesobjets;23 import org.junit.After;4 import org.junit.Assert;5 import org.junit.Before;6 import org.junit.Test;78 public class TestEquals {9 private Parent p; private Enfant e, e2;

    10 @Before public void setUp() throws Exception {11 p = new Parent (1); e = new Enfant(1, 2); e2 = new Enfant (1,2); }12 @After public void tearDown () throws Exception {13 p = null; e = null; e2 = null; }14 @Test public void testReflexivite () {15 Assert.assertTrue(p.equals(p) && e.equals(e) && e2.equals(e2)); }16 @Test public void testSymetrie () {17 Assert.assertTrue ((!p.equals(e)||e.equals(p))&&(!e.equals(p)||p.equals(e))); }18 @Test public void testTransitivity () {19 Assert.assertTrue(e2.equals(p) && p.equals(e) && e2.equals(e)); } }

    Télécom SudParis — Denis Conan — Janvier 2021 — CSC4102 16

  • Pour aller plus loin : idiomes Idiomes JAVA, exemples, méthodes de la classe Object

    # 16

    '

    &

    $

    %

    2.2 Clonage d’objet, méthode clone

    ■ Repris de l’Item 11 de [Bloch, 2008]

    ■ Particularité de cette méthode♦ Utilisation par une interface Cloneablea

    ■ Avec la déclaration de mise en œuvre de l’interface♦ clone retourne un objet qui est une copie attribut par attribut de l’objet sur

    laquelle elle est appelée▶ Cf. diapositives suivantes sur les concepts « clonage » et « copies légère et

    profonde »

    ■ Sans la déclaration de mise en œuvre de l’interface♦ Levée de l’exception CloneNotSupportedException

    a. La méthode Clone de Object est protected

    Télécom SudParis — Denis Conan — Janvier 2021 — CSC4102 17

  • Idiomes JAVA, exemples, méthodes de la classe Object 2.2 Clonage d’objet, méthode clone

    # 17

    '

    &

    $

    %

    2.2.1 Concept du clonage

    ■ Les objets sont manipulés par des références ⇒♦ o2 = o1 : copie la référence o1 dans o2

    o1

    obj1

    obj2

    o2 o2

    obj1

    obj2

    o1

    "Paul"

    "Jean" "Jean"

    "Paul"

    ♦ o2 = o1.clone() : o2 référence un nouvel objet (copie de o1)

    o1

    o2 o2

    o1

    "Paul"

    "Jean""Jean"

    "Paul"

    "Jean"

    La classe Object propose une copie légère par un clonage basé sur la copie champ par champ réaliséepar affectation : elle n’appelle pas récursivement la méthode clone() (pour cette raison, la copie est appeléelégère). Cette opération de clonage par défaut n’est possible que si la classe réalise (implements) l’interfacejava.lang.Cloneable. Si ce n’est pas le cas, l’exception CloneNotSupportedException est levée. Cettecopie champ par champ est suffisante pour avoir deux objets indépendants lorsque les objets copiés necontiennent pas de référence.

    Lorsque les objets contiennent des références, il faut définir la méthode clone() pour cette classe, maisaussi pour toutes les classes référencées par celle-ci, afin de réaliser une copie récursive dite « copie profonde ».

    La méthode clone est protected dans la classe Object afin de restreindre l’utilisation de cette méthodeaux classes et à leurs classes filles. Si le clonage est garanti (par la redéfinition de la méthode clone), celle-cidoit devenir publique.

    Télécom SudParis — Denis Conan — Janvier 2021 — CSC4102 18

  • Idiomes JAVA, exemples, méthodes de la classe Object 2.2 Clonage d’objet, méthode clone

    # 18

    '

    &

    $

    %

    2.2.2 Diagramme de classes exemple pour présenter le clonage

    nbTotalParticipationsnbTotalOrganisationsnbParticipationsnbOrganisationsprenomnom

    nbTotalScrutin

    Choix

    /nbBulletinsPour/nbBulletinsContre*

    ScrutinPréférences

    nbTotal

    intituléPréférencetexteCommentairePréf

    Préférence

    *

    Personne

    pourOuContre

    Bulletin

    *

    * *

    *

    *

    Studs

    concerne

    co

    nc

    ern

    e

    concerne

    organise

    *

    *

    PlageHoraire

    dateheureDébutheureFin

    *

    ScrutinPlagesHoraires

    nbTotal

    intituléScrutintexteCommentaireScrutindateCréationdateDébutdateLimitedateLimiteExistence

    Scrutin

    ouvertureAvancéefermetureAvancéedestructionAvancée

    /nbChoix

    Nous voulons réaliser une méthode clone qui fonctionne pour la paire Scrutin et Personne.La difficulté de ce clonage tient au fait que la relation est bidirectionnelle. Il faut donc être capable de

    dupliquer les deux objets et de ne pas avoir d’incohérence d’association entre ces objets.

    Télécom SudParis — Denis Conan — Janvier 2021 — CSC4102 19

  • Idiomes JAVA, exemples, méthodes de la classe Object 2.2 Clonage d’objet, méthode clone

    # 19

    '

    &

    $

    %

    2.2.3 Représentation graphique d’une copie légère

    p:

    :String

    = "Julien"

    :Personne

    nomprénomscrutins

    :String

    = "Dupont"

    p1:

    :Personne

    prénom

    scrutins

    nom

    :Scrutin

    organisateurnom

    :String

    = "Election bde"

    :ArrayList

    Classe seance7.methodescommunesatouslesobjets.clonageleger.Personne

    1 package eu.telecomsudparis.csc4102.cours.seance7.methodescommunesatouslesobjets.clonageleger;2 import java.util.ArrayList;34 public class Personne implements Cloneable {5 private String nom , prenom;6 private int nbOrg = 0;7 private ArrayList scrutins ;8 public Personne(String nom , String prenom){9 this.nom = nom; this.prenom = prenom; scrutins = new ArrayList (); }

    10 public Scrutin organiserScrutin(String nom) {11 scrutins.add(new Scrutin(nom ,this)); return scrutins.get(nbOrg ++); }12 @Override13 public Personne clone () throws CloneNotSupportedException {14 return (Personne) super.clone ();15 }16 public String getNom (){return nom;}17 public String getPrenom (){return prenom ;}18 public ArrayList getScrutins (){return scrutins ;}19 public void voter(Bulletin b){ }20 public void consulterResultat(Scrutin s) { }21 public void seRetirerDUnScrutin(Scrutin s) { }22 }

    Classe seance7.methodescommunesatouslesobjets.clonageleger.ExempleClonageLeger

    1 package eu.telecomsudparis.csc4102.cours.seance7.methodescommunesatouslesobjets.clonageleger;23 import java.util.ArrayList;45 public class ExempleClonageLeger {6 public static void main(final String [] args)7 throws CloneNotSupportedException {8 Personne p = new Personne("Dupont", "Julien");9 p.organiserScrutin("Election␣bde");

    10 Personne p1 = p.clone();11 if (p1 == p) {12 System.out.println("p␣==␣p1");13 }14 if (p.getNom ().equals(p1.getNom ())) {15 System.out.println("p␣et␣p1␣noms␣==");16 }17 if (p.getPrenom ().equals(p1.getPrenom ())) {18 System.out.println("p␣et␣p1␣prenoms␣==");19 }20 ArrayList a1, a2;21 a1 = p.getScrutins ();22 a2 = p1.getScrutins ();23 if (a1 == a2) {24 System.out.println("p␣et␣p1␣scrutins␣==");25 } else {26 for (int i = 0; i < a1.size(); i++) {

    Télécom SudParis — Denis Conan — Janvier 2021 — CSC4102 20

  • Idiomes JAVA, exemples, méthodes de la classe Object 2.2 Clonage d’objet, méthode clone

    27 if (a1.get(i) == a2.get(i)) {28 System.out.println("Scrutin␣de␣rang␣" + i + "␣==");29 }30 }31 }32 }33 }

    p et p1 noms ==p et p1 prenoms ==p et p1 scrutins ==

    Dans cet exemple, la classe Personne implémente l’interface Clonable en réalisant le clonage par l’uti-lisation de la méthode clone héritée de la classe Object. L’objet obtenu est bien distinct de l’objet initial.Par contre, les objets référencés par les deux objets, à savoir le nom, le prénom et le tableau de Scrutinn’ont pas été dupliqués et donc ils sont partagés par les deux objets de type Personne.

    Télécom SudParis — Denis Conan — Janvier 2021 — CSC4102 21

  • Idiomes JAVA, exemples, méthodes de la classe Object 2.2 Clonage d’objet, méthode clone

    # 20

    '

    &

    $

    %

    2.2.4 Représentation graphique d’une copie plus profondep:

    :Personne

    nomprénomscrutins

    :String

    = "Julien"

    :String

    = "Dupont"

    :String

    = "Julien"

    :String

    = "Dupont"

    :Scrutin

    organisateurnom

    :String

    = "Election bde"

    :ArrayList :ArrayList

    p1:

    :Personne

    prénom

    scrutins

    nom

    Classe seance7.methodescommunesatouslesobjets.clonageplusprofond.Personne

    1 package eu.telecomsudparis.csc4102.cours.seance7.methodescommunesatouslesobjets.clonageplusprofond;2 import java.util.ArrayList;34 public class Personne implements Cloneable {5 private String nom , prenom;6 private int nbParticipations = 0, nbOrg = 0;7 private ArrayList scrutins;8 public Personne(final String n, final String p) {9 this.nom = n;

    10 this.prenom = p;11 scrutins = new ArrayList ();12 }13 public Scrutin organiserScrutin(final String nom) {14 Scrutin s = new Scrutin(nom ,this);15 scrutins.add(s);16 nbOrg ++;17 return s;18 }19 /** le clonage est profond , il duplique les objets references */20 @SuppressWarnings("unchecked")21 @Override22 public Personne clone () throws CloneNotSupportedException {23 Personne clone = new Personne(nom , prenom);24 clone.nbParticipations = nbParticipations;25 clone.nbOrg = nbOrg;26 clone.scrutins = (ArrayList ) scrutins.clone ();27 return clone;28 }29 public String getNom () { return nom; }30 public String getPrenom () {return prenom; }31 public ArrayList getScrutins () {return scrutins; }32 public void voter(final Bulletin b){ }33 public void consulterResultat(Scrutin s) { }34 public void seRetirerDUnScrutin(Scrutin s) { }35 }

    Classe seance7.methodescommunesatouslesobjets.clonageplusprofond.ExempleClonagePlusProfond

    1 package eu.telecomsudparis.csc4102.cours.seance7.methodescommunesatouslesobjets.clonageplusprofond;2 import java.util.ArrayList;3 public class ExempleClonagePlusProfond {4 public static void main(final String [] args)5 throws CloneNotSupportedException {6 Personne p = new Personne("Dupont", "Julien");7 p.organiserScrutin("Election␣bde");8 Personne p1 = p.clone();9 if (p1 == p) {

    10 System.out.println("p␣==␣p1");11 }12 if (p.getNom () == p1.getNom ()) {13 System.out.println("p␣et␣p1␣noms␣==");

    Télécom SudParis — Denis Conan — Janvier 2021 — CSC4102 22

  • Idiomes JAVA, exemples, méthodes de la classe Object 2.2 Clonage d’objet, méthode clone

    14 }15 if (p.getPrenom () == p1.getPrenom ()) {16 System.out.println("p␣et␣p1␣prenoms␣==");17 }18 ArrayList a1, a2;19 a1 = p.getScrutins ();20 a2 = p1.getScrutins ();21 if (a1 == a2) {22 System.out.println("p␣et␣p1␣scrutins␣==");23 } else {24 for(int i = 0; i < a1.size(); i++) {25 if(a1.get(i) == a2.get(i)) {26 System.out.println("Scrutins␣de␣rang␣" + i +"␣==");27 } else {28 if(a1.get(i).getOrganisateur () == a2.get(i).getOrganisateur ()) {29 System.out.println("Oraganisateur␣des␣scrutins␣de␣rang" + i +"==");30 }31 }32 }33 }34 }35 }

    Résultat de l’exécution :p et p1 noms ==p et p1 prenoms ==Scrutins de rang 0 ==

    Télécom SudParis — Denis Conan — Janvier 2021 — CSC4102 23

  • Idiomes JAVA, exemples, méthodes de la classe Object 2.2 Clonage d’objet, méthode clone

    # 21

    '

    &

    $

    %

    2.2.5 Représentation graphique d’une copie profondep:

    :Personne

    nomprénomscrutins

    :String

    = "Julien"

    :String

    = "Dupont"

    :String

    = "Julien"

    :String

    = "Dupont"

    :ArrayList :ArrayList

    :Scrutin

    organisateurnom

    :Scrutin

    organisateurnom

    :String

    = "Election bde"

    :String

    = "Election bde"

    p1:

    :Personne

    prénom

    scrutins

    nom

    Classe seance7.methodescommunesatouslesobjets.clonageprofond.Scruptin

    1 package eu.telecomsudparis.csc4102.cours.seance7.methodescommunesatouslesobjets.clonageprofond;23 public class Scrutin implements Cloneable {4 private Personne organisateur;5 private String nomScrutin;6 public Scrutin(final String nom , final Personne organisateur) {7 nomScrutin = nom;8 this.organisateur = organisateur;9 }

    10 /** le clonage duplique le nom mais ne peut pas modifier l’ organisateur .11 * En effet le clonage de l’ organisation clone les scrutins qu ’il a12 * organise et nous entrerions dans une cascade d’appels infinie13 **/14 @Override15 public Scrutin clone() throws CloneNotSupportedException {16 return new Scrutin(new String(nomScrutin), organisateur);17 }18 /** Methode pour modifier l’ organisateur en cas de clonage . */19 void setOrganisateur(final Personne norg) {20 organisateur = norg;21 }22 public Personne getOrganisateur () {23 return organisateur;24 }25 }

    Scrutin contient deux attributs, une chaîne de caractères qui est clonable, et une référence sur l’organi-sateur du Scrutin. La méthode clone est définie entre les lignes 11 et 13. Elle fait appel à la méthode clonede la classe Object qui duplique les attributs de l’objet dans le clone.

    Nous voulons aussi que le clone du Scrutin puisse être associé avec la Personne lorsque celui-ci aura étéclonée. Pour cela, nous introduisons la méthode setOrganisateur().

    Classe seance7.methodescommunesatouslesobjets.clonageprofond.Personne

    1 package eu.telecomsudparis.csc4102.cours.seance7.methodescommunesatouslesobjets.clonageprofond;23 import java.util.ArrayList;45 public class Personne implements Cloneable {6 private String nom , prenom;7 private int nbParticipations = 0, nbOrg = 0;8 private ArrayList scrutins;9

    10 public Personne(final String n, final String p) {11 this.nom = n;12 this.prenom = p;13 scrutins = new ArrayList ();14 }

    Télécom SudParis — Denis Conan — Janvier 2021 — CSC4102 24

  • Idiomes JAVA, exemples, méthodes de la classe Object 2.2 Clonage d’objet, méthode clone

    1516 public Scrutin organiserScrutin(final String nom) {17 Scrutin s = new Scrutin(nom , this);18 scrutins.add(s);19 nbOrg ++;20 return s;21 }2223 /**24 * le clonage est profond , il duplique les objets references . Ce n’est pas25 * necessaire pour les objets du type String du fait qu ’un String est non26 * modifiable .27 */28 @Override29 public Personne clone () throws CloneNotSupportedException {30 Personne cl = new Personne(nom , prenom);31 cl.nbParticipations = nbParticipations;32 cl.nbOrg = nbOrg;33 for (Scrutin scr : scrutins) {34 Scrutin sclone = scr.clone ();35 sclone.setOrganisateur(cl);36 cl.scrutins.add(sclone);37 }38 return cl;39 }4041 public String getNom () {42 return nom;43 }4445 public String getPrenom () {46 return prenom;47 }4849 public ArrayList getScrutins () {50 return scrutins;51 }5253 public void voter(final Bulletin b) {54 }5556 public void consulterResultat(Scrutin s) {57 }5859 public void seRetirerDUnScrutin(Scrutin s) {60 }61 }

    Pour ce qui est de la personne, nous voulons la cloner et elle contient une liste des scrutins qu’elle aorganisés. Il faut donc que nous dupliquions cette liste, ce qui est possible puisqu’elle implémente l’interfaceCloneable. Il faut, cependant que la duplication soit profonde, c’est-à-dire que nous dupliquions les entréesde la liste.

    Cette duplication profonde commence par cloner l’objet courant. Pour cela elle, crée un objet copie parappel d’un constructeur à la ligne 23, auquel elle passe les paramètres nom et prenom. Elle modifie ensuiteles attributs nbOrg et nbParticipations en y mettant les valeurs des attributs correspondant dans l’objetcourant. Ensuite, à la ligne 25, la méthode parcourt les scrutins un à un. Pour chaque scrutin, un clone duscrutin est construit à la ligne 26. L’organisateur de ce scrutin cloné est associé avec la personne en cours declonage par la méthode setOrganisateur.

    Classe seance7.methodescommunesatouslesobjets.clonageprofond.ExempleClonageProfond

    1 package eu.telecomsudparis.csc4102.cours.seance7.methodescommunesatouslesobjets.clonageprofond;2 import java.util.ArrayList;3 public class ExempleClonageProfond {4 public static void main(final String [] args)5 throws CloneNotSupportedException {6 Personne p = new Personne("Dupont", "Julien");7 p.organiserScrutin("Election␣bde␣2010");8 Personne p1 = p.clone();9 if (p1 == p) {

    10 System.out.println("p␣==␣p1");11 }12 if (p.getNom () == p1.getNom ()) {13 System.out.println("p␣et␣p1␣noms␣==");14 }15 if (p.getPrenom () == p1.getPrenom ()) {16 System.out.println("p␣et␣p1␣prenoms␣==");17 }18 ArrayList a1, a2;19 a1 = p.getScrutins ();

    Télécom SudParis — Denis Conan — Janvier 2021 — CSC4102 25

  • Idiomes JAVA, exemples, méthodes de la classe Object 2.2 Clonage d’objet, méthode clone

    20 a2 = p1.getScrutins ();21 if (a1 == a2) {22 System.out.println("p␣et␣p1␣scrutins␣==");23 } else {24 for(int i = 0; i < a1.size(); i++) {25 if(a1.get(i) == a2.get(i)) {26 System.out.println("Scrutins␣de␣rang␣" + i +"␣==");27 } else {28 if(a1.get(i).getOrganisateur () == a2.get(i).getOrganisateur ()) {29 System.out.println("Oraganisateur␣des␣scrutins␣de␣rang" + i +"==");30 }31 }32 }33 }34 }35 }

    Résultat de l’exécution :p et p1 noms ==p et p1 prenoms ==

    Télécom SudParis — Denis Conan — Janvier 2021 — CSC4102 26

  • Pour aller plus loin: idiomes

    # 22

    '

    &

    $

    %

    3 Classes immuables/inaltérables

    ■ Repris de l’Item 15 de [Bloch, 2008]

    ■ Immuabilité/inaltérabilité (en anglais, immutability, immutable objects)♦ Une classe immuable est une classe dont les instances ne peuvent pas être

    modifiées♦ Que faire ?▶ Pas de méthode qui modifie l’état⋆ Pas d’accesseur⋆ Retourner une nouvelle instance lors des modifications (voir exemple)

    ▶ Classe final ou constructeur privé avec méthode static pour construire lesinstances (voir exemple)

    ▶ Tous les attributs private▶ Si des attributs sont des références⋆ Cloner les valeurs avant de les retourner

    ■ Exemple prototypique = la classe String

    C’est une bonne idée à tester dans vos codes que d’essayer d’écrire des classes immuables. Vous vouspréparerez à la programmation concurrente, car une instance qui ne change pas de valeur est facilementpartageable entre threads.

    Étudiez l’exemple suivant.Classe seance7.classesditesimmuables.NombreComplexe

    1 package eu.telecomsudparis.csc4102.cours.seance7.classesditesimmuables;23 public class NombreComplexe {4 private final double partieReelle;5 private final double partieImaginaire;6 public static final NombreComplexe ZERO = new NombreComplexe (0, 0);7 public static final NombreComplexe ONE = new NombreComplexe (1, 0);8 public static final NombreComplexe I = new NombreComplexe (0, 1);9

    10 private NombreComplexe(final double partieReelle ,11 final double partieImaginaire) {12 this.partieReelle = partieReelle;13 this.partieImaginaire = partieImaginaire;14 }1516 public static NombreComplexe valueOf(final double partieReelle ,17 final double partieImaginaire) {18 return new NombreComplexe(partieReelle , partieImaginaire);19 }2021 public static NombreComplexe valueOfPolar(final double r,22 final double theta) {23 return new NombreComplexe(r * Math.cos(theta), r * Math.sin(theta));24 }2526 public double partieReelle () {27 return partieReelle;28 }2930 public double PartieImaginaire () {31 return partieImaginaire;32 }3334 public NombreComplexe ajouter(NombreComplexe c) {35 return new NombreComplexe(partieReelle + c.partieReelle ,36 partieImaginaire + c.partieImaginaire);37 }3839 public NombreComplexe soustraire(NombreComplexe c) {40 return new NombreComplexe(partieReelle - c.partieReelle ,41 partieImaginaire - c.partieImaginaire);42 }43

    Télécom SudParis — Denis Conan — Janvier 2021 — CSC4102 27

  • Pour aller plus loin : idiomes

    44 public NombreComplexe multiplier(NombreComplexe c) {45 return new NombreComplexe(46 partieReelle * c.partieReelle47 - partieImaginaire * c.partieImaginaire ,48 partieReelle * c.partieImaginaire49 + partieImaginaire * c.partieReelle);50 }5152 public NombreComplexe diviser(NombreComplexe c) {53 double tmp = c.partieReelle * c.partieReelle54 + c.partieImaginaire * c.partieImaginaire;55 return new NombreComplexe(56 (partieReelle * c.partieReelle57 + partieImaginaire * c.partieImaginaire) / tmp ,58 (partieImaginaire * c.partieReelle59 - partieReelle * c.partieImaginaire) / tmp);60 }6162 @Override63 public boolean equals(Object obj) {64 if (this == obj)65 return true;66 if (obj == null)67 return false;68 if (getClass () != obj.getClass ())69 return false;70 NombreComplexe other = (NombreComplexe) obj;71 if (Double.doubleToLongBits(partieImaginaire) != Double72 .doubleToLongBits(other.partieImaginaire))73 return false;74 if (Double.doubleToLongBits(partieReelle) != Double75 .doubleToLongBits(other.partieReelle))76 return false;77 return true;78 }7980 @Override81 public int hashCode () {82 final int prime = 31;83 int result = 1;84 long temp;85 temp = Double.doubleToLongBits(partieImaginaire);86 result = prime * result + (int) (temp ^ (temp >>> 32));87 temp = Double.doubleToLongBits(partieReelle);88 result = prime * result + (int) (temp ^ (temp >>> 32));89 return result;90 }9192 @Override93 public String toString () {94 return "(" + partieReelle + "␣+␣" + partieImaginaire + "i)";95 }96 }

    Télécom SudParis — Denis Conan — Janvier 2021 — CSC4102 28

  • Pour aller plus loin : idiomes 3 Classes immuables/inaltérables

    # 23

    '

    &

    $

    %

    3.1 Cas des collections immuables

    ■ Lorsqu’une classe immuable contient un attribut de type collectionClasse seance7.classesditesimmuables.MauvaisFinalStaticTableau

    1 public static final String [] TABLEAU = {"un", "deux", "trois"};

    Classe seance7.classesditesimmuables.MeilleursFinalStaticTableau

    1 private static final String [] TABLEAU = { "un", "deux", "trois" };2 public static final List TAB = Collections.unmodifiableList(Arrays.

    asList(TABLEAU));3 public String [] autreSolutionAvecGetterEtClone () { return TABLEAU.clone (); }

    Classe seance7.classesditesimmuables.ExempleModificationTableauFinalStatic

    1 System.out.println(new MauvaisFinalStaticTableau ());2 MauvaisFinalStaticTableau.TABLEAU [0] = "deux";3 System.out.println(new MauvaisFinalStaticTableau ());4 try { MeilleursFinalStaticTableau.TAB.remove (0); }5 catch (UnsupportedOperationException e) { System.out.println(e); }6 MeilleursFinalStaticTableau m = new MeilleursFinalStaticTableau ();7 String [] tab = m.autreSolutionAvecGetterEtClone (); tab[0] = "deux";8 System.out.println("tab[0]␣=␣" + tab [0]); System.out.println(m);

    Voici ce que donne l’exécution :ErreurFinalStaticTableau [ un deux trois ]ErreurFinalStaticTableau [ deux deux trois ]java.lang.UnsupportedOperationExceptiontab[0] = deuxMeilleurFinalStaticTableau [ un deux trois ]

    Dans cet exemple, le programmeur souhaite mettre à disposition un tableau (une collection)constante : il faut que l’attribut soit final et que le contenu de la collection référencée soit lui-aussinon modifiable. L’exemple d’exécution montre que mettre l’attribut final n’est pas suffisant (classeMauvaisFinalStaticTableau). Il montre aussi qu’essayer de modifier une collection immuable génère uneexception (classe MeilleursFinalStaticTableau et exception UnsupportedOperationException).

    Télécom SudParis — Denis Conan — Janvier 2021 — CSC4102 29

  • Pour aller plus loin : idiomes

    # 24

    '

    &

    $

    %

    Bibliographie

    [Bloch, 2008] Bloch, J. (2008). Effective Java, 2nd Edition. Addison-Wesley.

    [Class Object, JSE8] Class Object (JSE8). Javadoc of the class Object of JAVA SE 8.https://docs.oracle.com/javase/9/docs/api/index.html?java/lang/Object.html.

    [Gosling et al., 2015] Gosling, J., Joy, B., Steele, G., Bracha, G., and Buckley, A.(2015). The Java Language Specification, Java SE 8 Edition.https://docs.oracle.com/javase/specs/jls/se8/jls8.pdf.

    Télécom SudParis — Denis Conan — Janvier 2021 — CSC4102 30