• Aucun résultat trouvé

Pour aller plus loin : idiomes

N/A
N/A
Protected

Academic year: 2022

Partager "Pour aller plus loin : idiomes"

Copied!
30
0
0

Texte intégral

(1)

Pour aller plus loin : idiomes

Denis Conan avec Christian Bac

CSC4102

(2)

Pour aller plus loin : idiomes

Table des matières

Pour aller plus loin : idiomes

Denis Conan, avec Christian Bac, Télécom SudParis, CSC4102

Janvier 2022 1

Sommaire 3

1 Création et destruction d’objets 4

1.1 Intérêt des méthodes de classe pour la création . . . . 5

1.2 Problème du constructeur dépendant d’une méthode rédéfinie . . . . 6

1.3 Création d’objet avec beaucoup d’attributs, certains optionnels . . . . 7

1.4 Non-instanciabilité d’une classe . . . . 8

1.5 Éviter la création inutile d’objet . . . . 9

1.6 Éviter le concept de finalizer des classes . . . . 10

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

2.1.1 Exemple d’erreur sur la propriété de symétrie . . . . 13

2.1.2 Exemple d’erreur sur la propriété de transitivité . . . . 14

2.1.3 Leçons à retenir suite à l’étude des 2 exemples précédents . . . . 15

2.1.4 Tests des propriétés de equals . . . . 16

2.2 Clonage d’objet, méthode clone . . . . 17

2.2.1 Concept du clonage . . . . 18

2.2.2 Diagramme de classes exemple pour présenter le clonage . . . . 19

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

2.2.4 Représentation graphique d’une copie plus profonde . . . . 22

2.2.5 Représentation graphique d’une copie profonde . . . . 24

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

Bibliographie 30

(3)

Pour aller plus loin : idiomes

# 2

'

&

$

%

Sommaire

1 Création et destruction d’objets . . . 3 2 Idiomes JAVA, exemples, méthodes de la classe Object communes à tous les objets10 3 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 de l’équipe de conception du langage JAVA : J. Bloch, « JAVA efficace », 2nd Edition, 2008. Nous ne pouvons que conseiller la lecture de cet ouvrage. Nous insérons ici des éléments directement en lien avec le module CSC4102.

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

Nous commençons par étudier la création et la destruction d’objets. Puis, nous revenons sur certaines

des méthodes communes à tous les objets.

(4)

Pour aller plus loin : idiomes

# 3

'

&

$

%

1 Création et destruction d’objets

1.1 Intérêt des méthodes de classe pour la création . . . 4

1.2 Problème du constructeur dépendant d’une méthode rédéfinie . . . 5

1.3 Création d’objet avec beaucoup d’attributs, certains optionnels . . . 6

1.4 Non-instanciabilité d’une classe . . . 7

1.5 Éviter la création inutile d’objet . . . 8

1.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. La

conception de bibliothèque met en œuvre des idiomes plus complexes ou plus subtiles.

(5)

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

# 4

'

&

$

%

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

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

■ Intérêts des méthodes de classe :

♦ 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 classe pour construire tous les types de 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<String, String> dictionnaire = newInstance();

Exemple de méthode de classe dans la bibliothèque des collections :

Classeseance7.creationdestructiondesobjets.CreationParMethodeDeClasse

1 p u b l i c c l a s s C r e a t i o n P a r M e t h o d e D e C l a s s e {

2 @ S u p p r e s s W a r n i n g s ( " u n u s e d " ) // p o u r e v i t e r le w a r n i n g d a n s E c l i p s e

3 p u b l i c s t a t i c v o i d m a i n ( S t r i n g [] a r g s ) {

4 List < String > l = C o l l e c t i o n s . s i n g l e t o n L i s t ( " un " ) ;

5 S y s t e m . out . p r i n t l n ( " l ␣ i n s t a n c e o f ␣ L i s t ␣ = ␣ " + ( l i n s t a n c e o f L i s t )

6 + " \ nl ␣ de ␣ t y p e ␣ \" " + l . g e t C l a s s () + " \" " ) ;

7 // c o n s t r u c t i o n m o i n s v e r b e u s e : d2 m o i n s v e r b e u x q u e d1

8 HashMap < String , String > d1 = n e w HashMap < String , String >() ;

9 HashMap < String , String > d2 = n e w I n s t a n c e () ;

10 }

11 p r i v a t e s t a t i c <C , V > HashMap < C , V > n e w I n s t a n c e () {

12 r e t u r n n e w HashMap < C , V >() ;

13 }

14 }

Résultat de l’exécution : l instanceof List = true

l de type "class java.util.Collections$SingletonList"

(6)

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

# 5

'

&

$

%

1.2 Problème du constructeur dépendant d’une méthode ré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

Classeseance7.creationdestructiondesobjets.ParentConstructeurDependantMethodeRedefinie

1 p u b l i c c l a s s P a r e n t C o n s t r u c t e u r D e p e n d a n t M e t h o d e R e d e f i n i e {

2 p u b l i c P a r e n t C o n s t r u c t e u r D e p e n d a n t M e t h o d e R e d e f i n i e () { m e t h o d e R e d e f i n i e () ; }

3 p u b l i c v o i d m e t h o d e R e d e f i n i e () { } }

Classeseance7.creationdestructiondesobjets.EnfantConstructeurDependantMethodeRedefinie

1 p u b l i c c l a s s E n f a n t C o n s t r u c t e u r D e p e n d a n t M e t h o d e R e d e f i n i e

2 e x t e n d s P a r e n t C o n s t r u c t e u r D e p e n d a n t M e t h o d e R e d e f i n i e {

3 p u b l i c E n f a n t C o n s t r u c t e u r D e p e n d a n t M e t h o d e R e d e f i n i e () { s u p e r() ; }

4 @ O v e r r i d e p u b l i c v o i d m e t h o d e R e d e f i n i e () { S y s t e m . out . p r i n t l n ( " s u r p r i s e " ) ; } }

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

Classeseance7.creationdestructiondesobjets.ExempleConstructeurDependantMethodeRedefinie

1 p a c k a g e eu . t e l e c o m s u d p a r i s . c s c 4 1 0 2 . c o u r s . s e a n c e 7 . c r e a t i o n d e s t r u c t i o n d e s o b j e t s ;

2

3 p u b l i c c l a s s E x e m p l e C o n s t r u c t e u r D e p e n d a n t M e t h o d e R e d e f i n i e {

4 p u b l i c s t a t i c v o i d m a i n ( S t r i n g [] a r g s ) {

5 n e w P a r e n t C o n s t r u c t e u r D e p e n d a n t M e t h o d e R e d e f i n i e () ;

6 n e w E n f a n t C o n s t r u c t e u r D e p e n d a n t M e t h o d e R e d e f i n i e () ;

7 }

8 }

(7)

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

# 6

'

&

$

%

1.3 Création d’objet avec beaucoup d’attributs, certains optionnels

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

■ Nous aimons dans des langages comme Python écrire

def 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

Classeseance6.creationdestructiondesobjets.ClasseAvecBeaucoupDAttributs

1 p u b l i c c l a s s C l a s s e A v e c B e a u c o u p D A t t r i b u t s {

2 p r i v a t e i n t a ;

3 p r i v a t e d o u b l e b = 1 . 0 ;

4 p r i v a t e S t r i n g c = " v a l e u r ␣ par ␣ d e f a u t " ;

5 p u b l i c C l a s s e A v e c B e a u c o u p D A t t r i b u t s (f i n a l i n t a ) {

6 t h i s. a = a ;

7 }

8 p u b l i c C l a s s e A v e c B e a u c o u p D A t t r i b u t s b (f i n a l d o u b l e b ) {

9 t h i s. b = b ;

10 r e t u r n t h i s;

11 }

12 p u b l i c C l a s s e A v e c B e a u c o u p D A t t r i b u t s c (f i n a l S t r i n g c ) {

13 t h i s. c = c ;

14 r e t u r n t h i s;

15 }

16 @ O v e r r i d e

17 p u b l i c S t r i n g t o S t r i n g () {

18 r e t u r n " C l a s s e A v e c B e a u c o u p D A t t r i b u t s ␣ [ a = " + a + " , ␣ b = " + b + " , ␣ c = " + c

19 + " ] " ;

20 }

21 }

Classeseance6.creationdestructiondesobjets.CreationAvecIdiomeBuilder

1 p u b l i c c l a s s C r e a t i o n A v e c I d i o m e B u i l d e r {

2 p u b l i c s t a t i c v o i d m a i n ( S t r i n g [] a r g s ) {

3 C l a s s e A v e c B e a u c o u p D A t t r i b u t s o = (n e w C l a s s e A v e c B e a u c o u p D A t t r i b u t s (1) )

4 . b ( 2 . 0 ) . c ( " a u t r e " ) ;

5 S y s t e m . out . p r i n t l n ( o ) ;

6 }

7 }

Résultat de l’exécution :

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

(8)

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é

Classeseance6.creationdestructiondesobjets.ClasseNonInstanciable

1 p u b l i c c l a s s C l a s s e N o n I n s t a n c i a b l e {

2 p r i v a t e C l a s s e N o n I n s t a n c i a b l e () {

3 t h r o w n e w A s s e r t i o n E r r o r () ;

4 }

5 }

■ Contrainte gardée dans les classes enfants

public 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

(9)

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 pour ré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 are the values of constant expressions— are “interned” so as to share unique instances, using the method String.intern » [Gosling et al., 2015, page 36]

Classeseance6.creationdestructiondesobjets.EviterLaCreationInutileDObjet

1 f o r (i n t i = 0; i < 1 0 0 0 0 0 0 0 0 0 ; i ++) {

2 s = n e w S t r i n g ( " un " ) ;

3 }

4 f o r (i n t i = 0; i < 1 0 0 0 0 0 0 0 0 0 ; i ++) {

5 s = " un " ;

6 }

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

(10)

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 is reclaimed to give the object a last chance to clean up resources that would not otherwise 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

Classeseance6.creationdestructiondesobjets.ClasseAvecFinalizer

1 p u b l i c c l a s s C l a s s e A v e c F i n a l i z e r {

2 p r i v a t e i n t a ;

3 p u b l i c C l a s s e A v e c F i n a l i z e r (f i n a l i n t a ) {

4 t h i s. a = a ;

5 }

6 @ O v e r r i d e

7 p u b l i c v o i d f i n a l i z e () {

8 S y s t e m . out . p r i n t l n ( " e x e c u t i o n ␣ f i n a l i z e ␣ de ␣ " + t h i s) ;

9 }

10 @ O v e r r i d e

11 p u b l i c S t r i n g t o S t r i n g () {

12 r e t u r n " C l a s s e A v e c F i n a l i z e r ␣ [ a = " + a + " ] " ;

13 }

14 }

Classeseance6.creationdestructiondesobjets.ExempleClasseAvecFinalize

1 p u b l i c c l a s s E x e m p l e C l a s s e A v e c F i n a l i z e {

2 @ S u p p r e s s W a r n i n g s ( " u n u s e d " )

3 p u b l i c s t a t i c v o i d m a i n ( S t r i n g [] a r g s ) {

4 C l a s s e A v e c F i n a l i z e r o = n e w C l a s s e A v e c F i n a l i z e r (1) ;

5 }

6 }

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

(11)

Pour aller plus loin : idiomes

# 10

'

&

$

%

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

2.1 Méthode equals . . . 11 2.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 sont

non triviaux mais importants : nous pensons que vous pouvez les comprendre aujourd’hui. Ensuite, nous

introduisons une interface très utilisée pour cloner des objets, avec les concepts importants de copie légère

et copie profonde.

(12)

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 no information 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ération

des méthodes equals et hashCode avec notre IDE, mais en les programmant nous-mêmes, et de manière

originale. Nous tombons alors dans des erreurs.

(13)

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étrie

Classeseance7.methodescommunesatouslesobjets.EqualsErreurSymetrie

1 p u b l i c E q u a l s E r r e u r S y m e t r i e (f i n a l S t r i n g s ) { t h i s. s = s ; }

2 @ O v e r r i d e p u b l i c b o o l e a n e q u a l s ( O b j e c t obj ) {

3 if (t h i s == obj ) r e t u r n t r u e; if ( obj == n u l l) r e t u r n f a l s e;

4 E q u a l s E r r e u r S y m e t r i e o t h e r = ( E q u a l s E r r e u r S y m e t r i e ) obj ;

5 if ( s == n u l l) { if ( o t h e r . s != n u l l) r e t u r n f a l s e; }

6 e l s e if (! s . e q u a l s I g n o r e C a s e ( o t h e r . s ) ) r e t u r n f a l s e; r e t u r n t r u e; } } Classeseance7.methodescommunesatouslesobjets.EqualsErreurSymetrieEnfant

1 p u b l i c E q u a l s E r r e u r S y m e t r i e E n f a n t (f i n a l S t r i n g s ) { s u p e r( s ) ; }

2 @ O v e r r i d e p u b l i c b o o l e a n e q u a l s ( O b j e c t obj ) {

3 if (t h i s == obj ) r e t u r n t r u e; if ( obj == n u l l) r e t u r n f a l s e;

4 E q u a l s E r r e u r S y m e t r i e o t h e r = ( E q u a l s E r r e u r S y m e t r i e ) obj ;

5 if ( s == n u l l) { if ( o t h e r . s != n u l l) r e t u r n f a l s e; }

6 e l s e if (! s . e q u a l s ( o t h e r . s ) ) r e t u r n f a l s e; r e t u r n t r u e; } } Classeseance7.methodescommunesatouslesobjets.ExemplesMethodeEqualsErreurSymetrie

1 E q u a l s E r r e u r S y m e t r i e o1 = n e w E q u a l s E r r e u r S y m e t r i e ( " A v e c " ) ;

2 E q u a l s E r r e u r S y m e t r i e E n f a n t o2 = n e w E q u a l s E r r e u r S y m e t r i e E n f a n t ( " a v e c " ) ;

3 List < E q u a l s E r r e u r S y m e t r i e > l = n e w A r r a y L i s t < >() ; l . add ( o1 ) ;

4 S y s t e m . out . p r i n t l n ( o2 . e q u a l s ( o1 ) + " , ␣ " + o1 . e q u a l s ( o2 ) + " , ␣ " + l . c o n t a i n s ( o2 ) ) ;

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

Voici les codes complets.

Classeseance7.methodescommunesatouslesobjets.EqualsErreurSymetrie

1 p a c k a g e eu . t e l e c o m s u d p a r i s . c s c 4 1 0 2 . c o u r s . s e a n c e 7 . m e t h o d e s c o m m u n e s a t o u s l e s o b j e t s ;

2

3 p u b l i c c l a s s E q u a l s E r r e u r S y m e t r i e {

4 S t r i n g s ;

5 p u b l i c E q u a l s E r r e u r S y m e t r i e (f i n a l S t r i n g s ) { t h i s. s = s ; }

6 @ O v e r r i d e p u b l i c b o o l e a n e q u a l s ( O b j e c t obj ) {

7 if (t h i s == obj ) r e t u r n t r u e; if ( obj == n u l l) r e t u r n f a l s e;

8 E q u a l s E r r e u r S y m e t r i e o t h e r = ( E q u a l s E r r e u r S y m e t r i e ) obj ;

9 if ( s == n u l l) { if ( o t h e r . s != n u l l) r e t u r n f a l s e; }

10 e l s e if (! s . e q u a l s I g n o r e C a s e ( o t h e r . s ) ) r e t u r n f a l s e; r e t u r n t r u e; } }

Classeseance7.methodescommunesatouslesobjets.ExemplesMethodeEqualsErreurSymetrie

1 p a c k a g e eu . t e l e c o m s u d p a r i s . c s c 4 1 0 2 . c o u r s . s e a n c e 7 . m e t h o d e s c o m m u n e s a t o u s l e s o b j e t s ;

2

3 i m p o r t j a v a . u t i l . A r r a y L i s t ;

4 i m p o r t j a v a . u t i l . L i s t ;

5

6 p u b l i c c l a s s E x e m p l e s M e t h o d e E q u a l s E r r e u r S y m e t r i e {

7 p u b l i c s t a t i c v o i d m a i n ( S t r i n g [] a r g s ) {

8 E q u a l s E r r e u r S y m e t r i e o1 = n e w E q u a l s E r r e u r S y m e t r i e ( " A v e c " ) ;

9 E q u a l s E r r e u r S y m e t r i e E n f a n t o2 = n e w E q u a l s E r r e u r S y m e t r i e E n f a n t ( " a v e c " ) ;

10 List < E q u a l s E r r e u r S y m e t r i e > l = n e w A r r a y L i s t < >() ; l . add ( o1 ) ;

11 S y s t e m . out . p r i n t l n ( o2 . e q u a l s ( o1 ) + " , ␣ " + o1 . e q u a l s ( o2 ) + " , ␣ " + l . c o n t a i n s ( o2 ) ) ;

12 }

13 }

La méthode EqualsErreurSymetrie::equals utilise la méthode String::equalsIgnoreCase alors

que la méthode redéfinie dans la classe enfant EqualsErreurSymetrieEnfant utilise la méthode

String::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éthode

(14)

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é

Classeseance7.methodescommunesatouslesobjets.Parent

1 p u b l i c c l a s s P a r e n t { p r i v a t e i n t a ; // . . .

Classeseance7.methodescommunesatouslesobjets.EqualsErreurTransitivite

1 p u b l i c c l a s s E q u a l s E r r e u r T r a n s i t i v i t e e x t e n d s P a r e n t {

2 p r i v a t e i n t b ;

3 p u b l i c E q u a l s E r r e u r T r a n s i t i v i t e (f i n a l i n t a , f i n a l i n t b ) {s u p e r( a ) ;t h i s. b = b ;}

4 @ O v e r r i d e p u b l i c b o o l e a n e q u a l s ( O b j e c t obj ) {

5 if (t h i s == obj ) r e t u r n t r u e; if ( obj == n u l l) r e t u r n f a l s e;

6 if ( obj . g e t C l a s s () . e q u a l s ( P a r e n t .c l a s s) ) r e t u r n s u p e r. e q u a l s ( obj ) ;

7 E q u a l s E r r e u r T r a n s i t i v i t e o t h e r = ( E q u a l s E r r e u r T r a n s i t i v i t e ) obj ;

8 r e t u r n s u p e r. e q u a l s ( o t h e r ) && b == o t h e r . b ; } }

Classeseance7.methodescommunesatouslesobjets.ExemplesMethodeEqualsErreurTransitivite

1 P a r e n t p = n e w P a r e n t (1) ;

2 E q u a l s E r r e u r T r a n s i t i v i t e e1 = n e w E q u a l s E r r e u r T r a n s i t i v i t e (1 , 2) ;

3 E q u a l s E r r e u r T r a n s i t i v i t e e2 = n e w E q u a l s E r r e u r T r a n s i t i v i t e (1 , 3) ;

4 S y s t e m . out . p r i n t l n ( e1 . e q u a l s ( p ) + " , ␣ " + p . e q u a l s ( e2 ) + " , ␣ " + e1 . e q u a l s ( 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.

Classeseance7.methodescommunesatouslesobjets.Parent

1 p a c k a g e eu . t e l e c o m s u d p a r i s . c s c 4 1 0 2 . c o u r s . s e a n c e 7 . m e t h o d e s c o m m u n e s a t o u s l e s o b j e t s ;

2

3 p u b l i c c l a s s P a r e n t { p r i v a t e i n t a ; // . . .

4 p u b l i c P a r e n t (f i n a l i n t a ) { t h i s. a = a ;}

5 @ O v e r r i d e p u b l i c b o o l e a n e q u a l s ( O b j e c t obj ) {

6 if (t h i s == obj ) r e t u r n t r u e;

7 if ( obj == n u l l) r e t u r n f a l s e;

8 if (!( obj i n s t a n c e o f P a r e n t ) ) r e t u r n f a l s e;

9 P a r e n t o t h e r = ( P a r e n t ) obj ;

10 if ( a != o t h e r . a ) r e t u r n f a l s e;

11 r e t u r n t r u e; } }

Classeseance7.methodescommunesatouslesobjets.EqualsErreurTransitivite

1 p a c k a g e eu . t e l e c o m s u d p a r i s . c s c 4 1 0 2 . c o u r s . s e a n c e 7 . m e t h o d e s c o m m u n e s a t o u s l e s o b j e t s ;

2

3 p u b l i c c l a s s E q u a l s E r r e u r T r a n s i t i v i t e e x t e n d s P a r e n t {

4 p r i v a t e i n t b ;

5 p u b l i c E q u a l s E r r e u r T r a n s i t i v i t e (f i n a l i n t a , f i n a l i n t b ) {s u p e r( a ) ;t h i s. b = b ;}

6 @ O v e r r i d e p u b l i c b o o l e a n e q u a l s ( O b j e c t obj ) {

7 if (t h i s == obj ) r e t u r n t r u e; if ( obj == n u l l) r e t u r n f a l s e;

8 if ( obj . g e t C l a s s () . e q u a l s ( P a r e n t .c l a s s) ) r e t u r n s u p e r. e q u a l s ( obj ) ;

9 E q u a l s E r r e u r T r a n s i t i v i t e o t h e r = ( E q u a l s E r r e u r T r a n s i t i v i t e ) obj ;

(15)

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 enfants

et 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’écrire vous-mêmes vos méthodes equals et hashCode

faites des vérifications dans votre projet

(Cf. diapositive qui suit)

(16)

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

# 15

'

&

$

%

2.1.4 Tests des propriétés de equals

Classeseance7.methodescommunesatouslesobjets.Parent

1 p u b l i c c l a s s P a r e n t { p r i v a t e i n t a ; // . . .

Classeseance7.methodescommunesatouslesobjets.Enfant

1 p u b l i c c l a s s E n f a n t e x t e n d s P a r e n t { p r i v a t e i n t b ;

2 p u b l i c E n f a n t (f i n a l i n t a , f i n a l i n t b ) { s u p e r( a ) ;t h i s. b = b ;} }

Classeseance7.methodescommunesatouslesobjets.TestEquals

1 p u b l i c c l a s s T e s t E q u a l s {

2 p r i v a t e P a r e n t p ; p r i v a t e E n f a n t e , e2 ;

3 @ B e f o r e p u b l i c v o i d s e t U p () t h r o w s E x c e p t i o n {

4 p = n e w P a r e n t (1) ; e = n e w E n f a n t (1 , 2) ; e2 = n e w E n f a n t (1 ,2) ; }

5 @ A f t e r p u b l i c v o i d t e a r D o w n () t h r o w s E x c e p t i o n {

6 p = n u l l; e = n u l l; e2 = n u l l; }

7 @ T e s t p u b l i c v o i d t e s t R e f l e x i v i t e () {

8 A s s e r t . a s s e r t T r u e ( p . e q u a l s ( p ) && e . e q u a l s ( e ) && e2 . e q u a l s ( e2 ) ) ; }

9 @ T e s t p u b l i c v o i d t e s t S y m e t r i e () {

10 A s s e r t . a s s e r t T r u e ((! p . e q u a l s ( e ) || e . e q u a l s ( p ) ) & & ( ! e . e q u a l s ( p ) || p . e q u a l s ( e ) ) ) ; }

11 @ T e s t p u b l i c v o i d t e s t T r a n s i t i v i t y () {

12 A s s e r t . a s s e r t T r u e ( e2 . e q u a l s ( p ) && p . e q u a l s ( e ) && e2 . e q u a l s ( e ) ) ; } }

Voici les codes complets.

Classeseance7.methodescommunesatouslesobjets.Parent

1 p a c k a g e eu . t e l e c o m s u d p a r i s . c s c 4 1 0 2 . c o u r s . s e a n c e 7 . m e t h o d e s c o m m u n e s a t o u s l e s o b j e t s ;

2

3 p u b l i c c l a s s P a r e n t { p r i v a t e i n t a ; // . . .

4 p u b l i c P a r e n t (f i n a l i n t a ) { t h i s. a = a ;}

5 @ O v e r r i d e p u b l i c b o o l e a n e q u a l s ( O b j e c t obj ) {

6 if (t h i s == obj ) r e t u r n t r u e;

7 if ( obj == n u l l) r e t u r n f a l s e;

8 if (!( obj i n s t a n c e o f P a r e n t ) ) r e t u r n f a l s e;

9 P a r e n t o t h e r = ( P a r e n t ) obj ;

10 if ( a != o t h e r . a ) r e t u r n f a l s e;

11 r e t u r n t r u e; } }

Classeseance7.methodescommunesatouslesobjets.Enfant

1 p a c k a g e eu . t e l e c o m s u d p a r i s . c s c 4 1 0 2 . c o u r s . s e a n c e 7 . m e t h o d e s c o m m u n e s a t o u s l e s o b j e t s ;

2

3 @ S u p p r e s s W a r n i n g s ( " u n u s e d " )

4 p u b l i c c l a s s E n f a n t e x t e n d s P a r e n t { p r i v a t e i n t b ;

5 p u b l i c E n f a n t (f i n a l i n t a , f i n a l i n t b ) { s u p e r( a ) ;t h i s. b = b ;} } Classeseance7.methodescommunesatouslesobjets.TestEquals

1 p a c k a g e eu . t e l e c o m s u d p a r i s . c s c 4 1 0 2 . c o u r s . s e a n c e 7 . m e t h o d e s c o m m u n e s a t o u s l e s o b j e t s ;

2

3 i m p o r t org . j u n i t . A f t e r ;

4 i m p o r t org . j u n i t . A s s e r t ;

5 i m p o r t org . j u n i t . B e f o r e ;

6 i m p o r t org . j u n i t . T e s t ;

(17)

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 Cloneable

a

■ 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 lequel 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éthodeClonedeObjectestprotected

(18)

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ée par affectation : elle n’appelle pas récursivement la méthode clone() (pour cette raison, la copie est appelée légère). Cette opération de clonage par défaut n’est possible que si la classe réalise (implements) l’interface java.lang.Cloneable. Si ce n’est pas le cas, l’exception CloneNotSupportedException est levée. Cette copie champ par champ est suffisante pour avoir deux objets indépendants lorsque les objets copiés ne contiennent pas de référence.

Lorsque les objets contiennent des références, il faut définir la méthode clone() pour cette classe, mais aussi 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éthode

aux classes et à leurs classes filles. Si le clonage est garanti (par la redéfinition de la méthode clone), celle-ci

doit devenir publique.

(19)

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

nbTotalParticipations nbTotalOrganisations nbParticipations nbOrganisations prenom nom

nbTotalScrutin

Choix /nbBulletinsPour /nbBulletinsContre

*

ScrutinPréférences nbTotal

intituléPréférence texteCommentairePréf

Préférence

*

Personne

pourOuContre Bulletin

*

* *

*

*

Studs

concerne

concerne

concerne organise

*

*

PlageHoraire date

heureDébut heureFin

*

ScrutinPlagesHoraires nbTotal

intituléScrutin texteCommentaireScrutin dateCréation

dateDébut dateLimite dateLimiteExistence

Scrutin

ouvertureAvancée fermetureAvancée destructionAvancé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.

(20)

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

nom prénom scrutins

:String

= "Dupont"

p1:

:Personne

prénom scrutins nom

:Scrutin

organisateur nom

:String

= "Election bde"

:ArrayList

Classeseance7.methodescommunesatouslesobjets.clonageleger.Personne

1 p a c k a g e eu . t e l e c o m s u d p a r i s . c s c 4 1 0 2 . c o u r s . s e a n c e 7 . m e t h o d e s c o m m u n e s a t o u s l e s o b j e t s . c l o n a g e l e g e r ;

2 i m p o r t j a v a . u t i l . A r r a y L i s t ;

3

4 p u b l i c c l a s s P e r s o n n e i m p l e m e n t s C l o n e a b l e {

5 p r i v a t e S t r i n g nom , p r e n o m ;

6 p r i v a t e i n t n b O r g = 0;

7 p r i v a t e A r r a y L i s t < Scrutin > s c r u t i n s ;

8 p u b l i c P e r s o n n e ( S t r i n g nom , S t r i n g p r e n o m ) {

9 t h i s. nom = nom ; t h i s. p r e n o m = p r e n o m ; s c r u t i n s = n e w A r r a y L i s t < Scrutin >() ; }

10 p u b l i c S c r u t i n o r g a n i s e r S c r u t i n ( S t r i n g nom ) {

11 s c r u t i n s . add (n e w S c r u t i n ( nom ,t h i s) ) ; r e t u r n s c r u t i n s . get ( n b O r g ++) ; }

12 @ O v e r r i d e

13 p u b l i c P e r s o n n e c l o n e () t h r o w s C l o n e N o t S u p p o r t e d E x c e p t i o n {

14 r e t u r n ( P e r s o n n e ) s u p e r. c l o n e () ;

15 }

16 p u b l i c S t r i n g g e t N o m () {r e t u r n nom ;}

17 p u b l i c S t r i n g g e t P r e n o m () {r e t u r n p r e n o m ;}

18 p u b l i c A r r a y L i s t < Scrutin > g e t S c r u t i n s () {r e t u r n s c r u t i n s ;}

19 p u b l i c v o i d v o t e r ( B u l l e t i n b ) { }

20 p u b l i c v o i d c o n s u l t e r R e s u l t a t ( S c r u t i n s ) { }

21 p u b l i c v o i d s e R e t i r e r D U n S c r u t i n ( S c r u t i n s ) { }

22 }

Classeseance7.methodescommunesatouslesobjets.clonageleger.ExempleClonageLeger

1 p a c k a g e eu . t e l e c o m s u d p a r i s . c s c 4 1 0 2 . c o u r s . s e a n c e 7 . m e t h o d e s c o m m u n e s a t o u s l e s o b j e t s . c l o n a g e l e g e r ;

2

3 i m p o r t j a v a . u t i l . A r r a y L i s t ;

4

(21)

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 S y s t e m . out . p r i n t l n ( " S c r u t i n ␣ de ␣ r a n g ␣ " + 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 Scrutin

n’ont pas été dupliqués et donc ils sont partagés par les deux objets de type Personne.

(22)

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 profonde

p:

:Personne

nom prénom scrutins

:String

= "Julien"

:String

= "Dupont"

:String

= "Julien"

:String

= "Dupont"

:Scrutin

organisateur nom

:String

= "Election bde"

:ArrayList :ArrayList p1:

:Personne

prénom scrutins nom

Classeseance7.methodescommunesatouslesobjets.clonageplusprofond.Personne

1 p a c k a g e eu . t e l e c o m s u d p a r i s . c s c 4 1 0 2 . c o u r s . s e a n c e 7 . m e t h o d e s c o m m u n e s a t o u s l e s o b j e t s . c l o n a g e p l u s p r o f o n d ;

2 i m p o r t j a v a . u t i l . A r r a y L i s t ;

3

4 p u b l i c c l a s s P e r s o n n e i m p l e m e n t s C l o n e a b l e {

5 p r i v a t e S t r i n g nom , p r e n o m ;

6 p r i v a t e i n t n b P a r t i c i p a t i o n s = 0 , n b O r g = 0;

7 p r i v a t e A r r a y L i s t < Scrutin > s c r u t i n s ;

8 p u b l i c P e r s o n n e (f i n a l S t r i n g n , f i n a l S t r i n g p ) {

9 t h i s. nom = n ;

10 t h i s. p r e n o m = p ;

11 s c r u t i n s = n e w A r r a y L i s t < Scrutin >() ;

12 }

13 p u b l i c S c r u t i n o r g a n i s e r S c r u t i n (f i n a l S t r i n g nom ) {

14 S c r u t i n s = n e w S c r u t i n ( nom ,t h i s) ;

15 s c r u t i n s . add ( s ) ;

16 n b O r g ++;

17 r e t u r n s ;

18 }

19 /* * le c l o n a g e e s t p r o f o n d , il d u p l i q u e l e s o b j e t s r e f e r e n c e s */

20 @ S u p p r e s s W a r n i n g s ( " u n c h e c k e d " )

21 @ O v e r r i d e

22 p u b l i c P e r s o n n e c l o n e () t h r o w s C l o n e N o t S u p p o r t e d E x c e p t i o n {

23 P e r s o n n e c l o n e = n e w P e r s o n n e ( nom , p r e n o m ) ;

24 c l o n e . n b P a r t i c i p a t i o n s = n b P a r t i c i p a t i o n s ;

25 c l o n e . n b O r g = n b O r g ;

26 c l o n e . s c r u t i n s = ( A r r a y L i s t < Scrutin >) s c r u t i n s . c l o n e () ;

27 r e t u r n c l o n e ;

28 }

p u b l i c S t r i n g g e t N o m () { r e t u r n nom ; }

(23)

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

14 }

15 if ( p . g e t P r e n o m () == p1 . g e t P r e n o m () ) {

16 S y s t e m . out . p r i n t l n ( " p ␣ et ␣ p1 ␣ p r e n o m s ␣ == " ) ;

17 }

18 A r r a y L i s t < Scrutin > a1 , a2 ;

19 a1 = p . g e t S c r u t i n s () ;

20 a2 = p1 . g e t S c r u t i n s () ;

21 if ( a1 == a2 ) {

22 S y s t e m . out . p r i n t l n ( " p ␣ et ␣ p1 ␣ s c r u t i n s ␣ == " ) ;

23 } e l s e {

24 f o r(i n t i = 0; i < a1 . s i z e () ; i ++) {

25 if( a1 . get ( i ) == a2 . get ( i ) ) {

26 S y s t e m . out . p r i n t l n ( " S c r u t i n s ␣ de ␣ r a n g ␣ " + i + " ␣ == " ) ;

27 } e l s e {

28 if( a1 . get ( i ) . g e t O r g a n i s a t e u r () == a2 . get ( i ) . g e t O r g a n i s a t e u r () ) {

29 S y s t e m . out . p r i n t l n ( " O r a g a n i s a t e u r ␣ des ␣ s c r u t i n s ␣ de ␣ r a n g " + 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 ==

(24)

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 profonde

p:

:Personne

nom prénom scrutins

:String

= "Julien"

:String

= "Dupont"

:String

= "Julien"

:String

= "Dupont"

:ArrayList :ArrayList

:Scrutin

organisateur nom

:Scrutin

organisateur nom :String

= "Election bde"

:String

= "Election bde"

p1:

:Personne

prénom scrutins nom

Classeseance7.methodescommunesatouslesobjets.clonageprofond.Scruptin

1 p a c k a g e eu . t e l e c o m s u d p a r i s . c s c 4 1 0 2 . c o u r s . s e a n c e 7 . m e t h o d e s c o m m u n e s a t o u s l e s o b j e t s . c l o n a g e p r o f o n d ;

2

3 p u b l i c c l a s s S c r u t i n i m p l e m e n t s C l o n e a b l e {

4 p r i v a t e P e r s o n n e o r g a n i s a t e u r ;

5 p r i v a t e S t r i n g n o m S c r u t i n ;

6 p u b l i c S c r u t i n (f i n a l S t r i n g nom , f i n a l P e r s o n n e o r g a n i s a t e u r ) {

7 n o m S c r u t i n = nom ;

8 t h i s. o r g a n i s a t e u r = o r g a n i s a t e u r ;

9 }

10 /* * le c l o n a g e d u p l i q u e le n o m m a i s ne p e u t p a s m o d i f i e r l ’ o r g a n i s a t e u r .

11 * En e f f e t le c l o n a g e de l ’ o r g a n i s a t i o n c l o n e l e s s c r u t i n s qu ’ il a

12 * o r g a n i s e et n o u s e n t r e r i o n s d a n s u n e c a s c a d e d ’ a p p e l s i n f i n i e

13 * */

14 @ O v e r r i d e

15 p u b l i c S c r u t i n c l o n e () t h r o w s C l o n e N o t S u p p o r t e d E x c e p t i o n {

16 r e t u r n n e w S c r u t i n (n e w S t r i n g ( n o m S c r u t i n ) , o r g a n i s a t e u r ) ;

17 }

18 /* * M e t h o d e p o u r m o d i f i e r l ’ o r g a n i s a t e u r en c a s de c l o n a g e . */

19 v o i d s e t O r g a n i s a t e u r (f i n a l P e r s o n n e n o r g ) {

20 o r g a n i s a t e u r = n o r g ;

21 }

22 p u b l i c P e r s o n n e g e t O r g a n i s a t e u r () {

23 r e t u r n o r g a n i s a t e u r ;

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 clone

(25)

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

15

16 p u b l i c S c r u t i n o r g a n i s e r S c r u t i n (f i n a l S t r i n g nom ) {

17 S c r u t i n s = n e w S c r u t i n ( nom , t h i s) ;

18 s c r u t i n s . add ( s ) ;

19 n b O r g ++;

20 r e t u r n s ;

21 }

22

23 /* *

24 * le c l o n a g e e s t p r o f o n d , il d u p l i q u e l e s o b j e t s r e f e r e n c e s . Ce n ’ e s t p a s

25 * n e c e s s a i r e p o u r l e s o b j e t s du t y p e S t r i n g du f a i t qu ’ un S t r i n g e s t n o n

26 * m o d i f i a b l e .

27 */

28 @ O v e r r i d e

29 p u b l i c P e r s o n n e c l o n e () t h r o w s C l o n e N o t S u p p o r t e d E x c e p t i o n {

30 P e r s o n n e cl = n e w P e r s o n n e ( nom , p r e n o m ) ;

31 cl . n b P a r t i c i p a t i o n s = n b P a r t i c i p a t i o n s ;

32 cl . n b O r g = n b O r g ;

33 f o r ( S c r u t i n scr : s c r u t i n s ) {

34 S c r u t i n s c l o n e = scr . c l o n e () ;

35 s c l o n e . s e t O r g a n i s a t e u r ( cl ) ;

36 cl . s c r u t i n s . add ( s c l o n e ) ;

37 }

38 r e t u r n cl ;

39 }

40

41 p u b l i c S t r i n g g e t N o m () {

42 r e t u r n nom ;

43 }

44

45 p u b l i c S t r i n g g e t P r e n o m () {

46 r e t u r n p r e n o m ;

47 }

48

49 p u b l i c A r r a y L i s t < Scrutin > g e t S c r u t i n s () {

50 r e t u r n s c r u t i n s ;

51 }

52

53 p u b l i c v o i d v o t e r (f i n a l B u l l e t i n b ) {

54 }

55

56 p u b l i c v o i d c o n s u l t e r R e s u l t a t ( S c r u t i n s ) {

57 }

58

59 p u b l i c v o i d s e R e t i r e r D U n S c r u t i n ( S c r u t i n s ) {

60 }

61 }

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

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

Classeseance7.methodescommunesatouslesobjets.clonageprofond.ExempleClonageProfond

1 p a c k a g e eu . t e l e c o m s u d p a r i s . c s c 4 1 0 2 . c o u r s . s e a n c e 7 . m e t h o d e s c o m m u n e s a t o u s l e s o b j e t s . c l o n a g e p r o f o n d ;

2 i m p o r t j a v a . u t i l . A r r a y L i s t ;

3 p u b l i c c l a s s E x e m p l e C l o n a g e P r o f o n d {

4 p u b l i c s t a t i c v o i d m a i n (f i n a l S t r i n g [] a r g s )

5 t h r o w s C l o n e N o t S u p p o r t e d E x c e p t i o n {

6 P e r s o n n e p = n e w P e r s o n n e ( " D u p o n t " , " J u l i e n " ) ;

7 p . o r g a n i s e r S c r u t i n ( " E l e c t i o n ␣ bde ␣ 2 0 1 0 " ) ;

8 P e r s o n n e p1 = p . c l o n e () ;

(26)

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

20 a2 = p1 . g e t S c r u t i n s () ;

21 if ( a1 == a2 ) {

22 S y s t e m . out . p r i n t l n ( " p ␣ et ␣ p1 ␣ s c r u t i n s ␣ == " ) ;

23 } e l s e {

24 f o r(i n t i = 0; i < a1 . s i z e () ; i ++) {

25 if( a1 . get ( i ) == a2 . get ( i ) ) {

26 S y s t e m . out . p r i n t l n ( " S c r u t i n s ␣ de ␣ r a n g ␣ " + i + " ␣ == " ) ;

27 } e l s e {

28 if( a1 . get ( i ) . g e t O r g a n i s a t e u r () == a2 . get ( i ) . g e t O r g a n i s a t e u r () ) {

29 S y s t e m . out . p r i n t l n ( " O r a g a n i s a t e u r ␣ des ␣ s c r u t i n s ␣ de ␣ r a n g " + i + " == " ) ;

30 }

31 }

32 }

33 }

34 }

35 }

Résultat de l’exécution :

p et p1 noms ==

p et p1 prenoms ==

(27)

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 les instances (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 vous préparerez à la programmation concurrente, car une instance qui ne change pas de valeur est facilement partageable entre threads.

Étudiez l’exemple suivant.

Classeseance7.classesditesimmuables.NombreComplexe

1 p a c k a g e eu . t e l e c o m s u d p a r i s . c s c 4 1 0 2 . c o u r s . s e a n c e 7 . c l a s s e s d i t e s i m m u a b l e s ;

2

3 p u b l i c c l a s s N o m b r e C o m p l e x e {

4 p r i v a t e f i n a l d o u b l e p a r t i e R e e l l e ;

5 p r i v a t e f i n a l d o u b l e p a r t i e I m a g i n a i r e ;

6 p u b l i c s t a t i c f i n a l N o m b r e C o m p l e x e Z E R O = n e w N o m b r e C o m p l e x e (0 , 0) ;

7 p u b l i c s t a t i c f i n a l N o m b r e C o m p l e x e ONE = n e w N o m b r e C o m p l e x e (1 , 0) ;

8 p u b l i c s t a t i c f i n a l N o m b r e C o m p l e x e I = n e w N o m b r e C o m p l e x e (0 , 1) ;

9

10 p r i v a t e N o m b r e C o m p l e x e (f i n a l d o u b l e p a r t i e R e e l l e ,

11 f i n a l d o u b l e p a r t i e I m a g i n a i r e ) {

12 t h i s. p a r t i e R e e l l e = p a r t i e R e e l l e ;

13 t h i s. p a r t i e I m a g i n a i r e = p a r t i e I m a g i n a i r e ;

14 }

15

16 p u b l i c s t a t i c N o m b r e C o m p l e x e v a l u e O f (f i n a l d o u b l e p a r t i e R e e l l e ,

17 f i n a l d o u b l e p a r t i e I m a g i n a i r e ) {

18 r e t u r n n e w N o m b r e C o m p l e x e ( p a r t i e R e e l l e , p a r t i e I m a g i n a i r e ) ;

19 }

20

21 p u b l i c s t a t i c N o m b r e C o m p l e x e v a l u e O f P o l a r (f i n a l d o u b l e r ,

22 f i n a l d o u b l e t h e t a ) {

23 r e t u r n n e w N o m b r e C o m p l e x e ( r * M a t h . cos ( t h e t a ) , r * M a t h . sin ( t h e t a ) ) ;

24 }

25

26 p u b l i c d o u b l e p a r t i e R e e l l e () {

27 r e t u r n p a r t i e R e e l l e ;

28 }

29

30 p u b l i c d o u b l e P a r t i e I m a g i n a i r e () {

31 r e t u r n p a r t i e I m a g i n a i r e ;

32 }

(28)

Pour aller plus loin : idiomes

44 p u b l i c N o m b r e C o m p l e x e m u l t i p l i e r ( N o m b r e C o m p l e x e c ) {

45 r e t u r n n e w N o m b r e C o m p l e x e (

46 p a r t i e R e e l l e * c . p a r t i e R e e l l e

47 - p a r t i e I m a g i n a i r e * c . p a r t i e I m a g i n a i r e ,

48 p a r t i e R e e l l e * c . p a r t i e I m a g i n a i r e

49 + p a r t i e I m a g i n a i r e * c . p a r t i e R e e l l e ) ;

50 }

51

52 p u b l i c N o m b r e C o m p l e x e d i v i s e r ( N o m b r e C o m p l e x e c ) {

53 d o u b l e tmp = c . p a r t i e R e e l l e * c . p a r t i e R e e l l e

54 + c . p a r t i e I m a g i n a i r e * c . p a r t i e I m a g i n a i r e ;

55 r e t u r n n e w N o m b r e C o m p l e x e (

56 ( p a r t i e R e e l l e * c . p a r t i e R e e l l e

57 + p a r t i e I m a g i n a i r e * c . p a r t i e I m a g i n a i r e ) / tmp ,

58 ( p a r t i e I m a g i n a i r e * c . p a r t i e R e e l l e

59 - p a r t i e R e e l l e * c . p a r t i e I m a g i n a i r e ) / tmp ) ;

60 }

61

62 @ O v e r r i d e

63 p u b l i c b o o l e a n e q u a l s ( O b j e c t obj ) {

64 if (t h i s == obj )

65 r e t u r n t r u e;

66 if ( obj == n u l l)

67 r e t u r n f a l s e;

68 if ( g e t C l a s s () != obj . g e t C l a s s () )

69 r e t u r n f a l s e;

70 N o m b r e C o m p l e x e o t h e r = ( N o m b r e C o m p l e x e ) obj ;

71 if ( D o u b l e . d o u b l e T o L o n g B i t s ( p a r t i e I m a g i n a i r e ) != D o u b l e

72 . d o u b l e T o L o n g B i t s ( o t h e r . p a r t i e I m a g i n a i r e ) )

73 r e t u r n f a l s e;

74 if ( D o u b l e . d o u b l e T o L o n g B i t s ( p a r t i e R e e l l e ) != D o u b l e

75 . d o u b l e T o L o n g B i t s ( o t h e r . p a r t i e R e e l l e ) )

76 r e t u r n f a l s e;

77 r e t u r n t r u e;

78 }

79

80 @ O v e r r i d e

81 p u b l i c i n t h a s h C o d e () {

82 f i n a l i n t p r i m e = 31;

83 i n t r e s u l t = 1;

84 l o n g t e m p ;

85 t e m p = D o u b l e . d o u b l e T o L o n g B i t s ( p a r t i e I m a g i n a i r e ) ;

86 r e s u l t = p r i m e * r e s u l t + (i n t) ( t e m p ^ ( t e m p > > > 32) ) ;

87 t e m p = D o u b l e . d o u b l e T o L o n g B i t s ( p a r t i e R e e l l e ) ;

88 r e s u l t = p r i m e * r e s u l t + (i n t) ( t e m p ^ ( t e m p > > > 32) ) ;

89 r e t u r n r e s u l t ;

90 }

91

92 @ O v e r r i d e

93 p u b l i c S t r i n g t o S t r i n g () {

94 r e t u r n " ( " + p a r t i e R e e l l e + " ␣ + ␣ " + p a r t i e I m a g i n a i r e + " i ) " ;

95 }

96 }

(29)

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 collection

Classeseance7.classesditesimmuables.MauvaisFinalStaticTableau

1 p u b l i c s t a t i c f i n a l S t r i n g [] T A B L E A U = { " un " , " d e u x " , " t r o i s " };

Classeseance7.classesditesimmuables.MeilleursFinalStaticTableau

1 p r i v a t e s t a t i c f i n a l S t r i n g [] T A B L E A U = { " un " , " d e u x " , " t r o i s " };

2 p u b l i c s t a t i c f i n a l List < String > TAB = C o l l e c t i o n s . u n m o d i f i a b l e L i s t ( A r r a y s . a s L i s t ( T A B L E A U ) ) ;

3 p u b l i c S t r i n g [] a u t r e S o l u t i o n A v e c G e t t e r E t C l o n e () { r e t u r n T A B L E A U . c l o n e () ; }

Classeseance7.classesditesimmuables.ExempleModificationTableauFinalStatic

1 S y s t e m . out . p r i n t l n (n e w M a u v a i s F i n a l S t a t i c T a b l e a u () ) ;

2 M a u v a i s F i n a l S t a t i c T a b l e a u . T A B L E A U [0] = " d e u x " ;

3 S y s t e m . out . p r i n t l n (n e w M a u v a i s F i n a l S t a t i c T a b l e a u () ) ;

4 t r y { M e i l l e u r s F i n a l S t a t i c T a b l e a u . TAB . r e m o v e (0) ; }

5 c a t c h ( U n s u p p o r t e d O p e r a t i o n E x c e p t i o n e ) { S y s t e m . out . p r i n t l n ( e ) ; }

6 M e i l l e u r s F i n a l S t a t i c T a b l e a u m = n e w M e i l l e u r s F i n a l S t a t i c T a b l e a u () ;

7 S t r i n g [] tab = m . a u t r e S o l u t i o n A v e c G e t t e r E t C l o n e () ; tab [0] = " d e u x " ;

8 S y s t e m . out . p r i n t l n ( " tab [0] ␣ = ␣ " + tab [ 0 ] ) ; S y s t e m . out . p r i n t l n ( m ) ;

Voici ce que donne l’exécution :

MauvaisFinalStaticTableau [ un deux trois ] MauvaisFinalStaticTableau [ deux deux trois ] java.lang.UnsupportedOperationException tab[0] = deux

MeilleurFinalStaticTableau [ 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-aussi

non modifiable. L’exemple d’exécution montre que mettre l’attribut final n’est pas suffisant (classe

MauvaisFinalStaticTableau). Il montre aussi qu’essayer de modifier une collection immuable génère une

exception (classe MeilleursFinalStaticTableau et exception UnsupportedOperationException).

(30)

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.

Références

Documents relatifs

- à condition de s'appuyer sur une pédagogie ac tive centrée su r l'expression, la communi- cation et le travail créatif (car que pourraient bien avoir à se dire

Soient (X, d) un espace métrique et A ⊂ X.. Pour obtenir 0iii, i.e. une forme bilinéaire symétrique dénie positive.. Par dénition même d'un fermé, cela signie que les intervalles

Facebook, Twitter… Les réseaux sociaux évoqués par les éditeurs permettent de se créer une communauté d’intérêts, de partager des informations, des idées, etc. C’est aussi

En effet, on ne peut envisager un bou- leversement dans des domaines aussi différents que la science des matériaux, l’électronique et les technologies de l’information, la biologie,

Travailler la résolution de problèmes en classe à partir d’Ateliers de Compréhension.

1 Un laser, placé en A, émet un rayon lumineux ; on souhaite que ce rayon soit dévié vers B, sachant que la lumière emprunte toujours le plus

1 Un laser, placé en A, émet un rayon lumineux ; on souhaite que ce rayon soit dévié vers B, sachant que la lumière emprunte toujours le plus

Encinas de Munagorri (dir.), Expertise et gouvernance du changement climatique, Paris, LGDJ,