Vous êtes sur la page 1sur 14

97.2.

La redfinition des mthodes equals() et hashCode()


La classe Object possde deux mthodes qui sont relatives l'identit des objets : equals() et hashCode().
La mthode equals() permet de tester l'galit de deux objets d'un point de vue smantique.
La mthode hashCode() permet de renvoyer la valeur de hachage de l'objet sur lequel elle est invoque.
Les spcifications imposent une rgle respecter lors de la redfinition de ces mthodes : si une classe
redfinit la mthode equals() alors elle doit aussi redfinir la mthode hashCode() et inversement. Le
comportement de ces deux mthodes doit tre symtrique : si les mthodes hashCode() et equals() sont
redfinies alors elles doivent utiliser, de prfrence, toutes les deux les mme champs car deux objets qui
sont gaux en utilisant la mthode equals() doivent obligatoirement avoir tous les deux la mme valeur de
retour lors de l'invocation de leur mthode hashCode(). L'inverse n'est pas forcment vrai.
Le hashcode ne fournit pas un identifiant unique pour un objet : de toute faon le hashcode d'un objet est
de type int, ce qui limiterait le nombre d'instances possibles d'une classe.
Deux objets pouvant avoir le mme hashcode, il faut alors utiliser la mthode equals() pour dterminer s'ils
sont identiques

97.2.1. Les contraintes pour redfinir equals() et hashCode()


Les mthodes equals() et hashCode() sont troitement lies.
La redfinition des mthodes equals() et hashcode() doit respecter quelques contraintes qui sont prcises
dans la documentation de la classe Object :

Symtrie : pour deux rfrences a et b, si a.equals(b) alors il faut obligatoirement que b.equals(a)

Rflexivit : pour toute rfrence non null, a.equals(a) doit toujours renvoyer true

Transitivit : si a.equals(b) et b.equals(c) alors a.equals(c)

Consistance avec la mthode hashCode() : si deux objets sont gaux en invoquant la mthode
equals() alors leur mthode hashCode() doit renvoyer la mme valeur pour les deux objets

Pour toute rfrence non null, a.equals(null) doit toujours renvoyer false

Aucune spcification n'est impose concernant l'implmentation des mthodes equals() et hashCode() pour
leur permettre d'tre consistantes.
Cependant, l'implmentation de la mthode hashcode() doit tre consistante avec la mthode equals() : si la
mthode equals() renvoie true pour deux objets alors la mthode hashCode() invoque sur les deux objets
doit renvoyer la mme valeur. L'inverse n'est pas vrai, deux objets dont la mthode hashCode() renvoie la
mme valeur, n'implique pas obligatoirement que l'invocation de la mthode equals() sur les deux objets
renvoie true.

Il est donc ncessaire de redfinir les mthodes hashCode() et equals() de manire coordonne si l'une ou
l'autre est redfinie. Pour garantir le contrat entre les mthodes equals() et hashCode() et leur efficacit
maximale, il est prfrable que leur implmentation utilise les mmes champs de la classe.
Pour les classes qui implmentent l'interface Comparable, il est aussi important de maintenir une cohrence
entre les mthodes equals() / hashCode() et la mthode compareTo(). Les spcifications prcisent que si la
mthode compareTo() renvoie 0 alors la mthode equals() doit renvoyer true et inversement. Cela implique
aussi que si equals() renvoie false, alors la mthode compareTo() doit renvoyer une valeur diffrente de 0.

97.2.2. La mthode equals()


L'oprateur == vrifie si deux objets sont identiques : il compare que les deux objets possdent la mme
rfrence mmoire et sont donc en fait le mme objet.
Deux objets identiques sont gaux mais deux objets gaux ne sont pas forcement identiques.
La mthode equals() vrifie l'galit de deux objets : son rle est de vrifier si deux instances sont
smantiquement quivalentes mme si ce sont deux instances distinctes.
Chaque classe peut avoir sa propre implmentation de l'galit mais gnralement deux objets sont gaux si
tout ou partie de leurs tats sont gaux.
Exemple :

01.public class TestEquals {


02.
03.public static void main(String[] args) {
04.String chaine1 = new String("test");
05.String chaine2 = new String("test");
06.boolean isSame = (chaine1 == chaine2);
07.System.out.println(isSame);
08.boolean isEqual = (chaine1.equals(chaine2));
09.System.out.println(isEqual);
10.}
11.}

Rsultat :

1.false
2.true

Deux mmes objets sont gaux s'ils possdent la mme rfrence videment mais deux objets distincts
peuvent aussi tre gaux si l'invocation de la mthode equals() du premier avec le second en paramtre
renvoie true.

97.2.2.1. L'implmentation par dfaut de la mthode equals()

L'implmentation par dfaut de la mthode equals() dans la classe Object est la suivante :
Exemple :

1.public boolean equals(Object obj) {


2.return (this == obj);
3.}

Par dfaut, l'implmentation de la mthode equals() hrite de la classe Object teste donc l'galit de
l'adresse mmoire des objets.
Il y a un contrat respecter entre les mthodes equals() et hashCode() : comme prcis dans la javadoc, si
l'invocation de la mthode equals() avec deux instances renvoie true alors l'invocation de la mthode
hashCode() de ces deux instances doit renvoyer la mme valeur. Cette implmentation respecte ce contrat.
Cette implmentation par dfaut de la mthode equals(), hrite de la classe Object, a le mrite de
fonctionner pour tous les objets mais son mode de fonctionnement n'est pas toujours souhait pour tous les
objets.
Exemple :

01.import java.util.Date;
02.
03.public class Personne {
04.
05.private String nom;
06.private String prenom;
07.private long id;
08.private Date dateNaiss;
09.private boolean adulte;
10.
11.public Personne(String nom, String prenom, long id, Date dateNaiss,
12.boolean adulte) {
13.super();
14.this.nom = nom;
15.this.prenom = prenom;
16.this.id = id;
17.this.dateNaiss = dateNaiss;
18.this.adulte = adulte;
19.}
20.}

Si l'on cre deux instances de cette classe avec les mme paramtres et que l'on teste l'galit sur les
deux instances, le rsultat est false puisque ce sont deux instances distinctes.
Exemple :

1.public class TestEqualsPersonne {


2.

3.public static void main(String[] args) {


4.Personne p1 = new Personne("nom1", "prenom1", 1, null, true);
5.Personne p2 = new Personne("nom1", "prenom1", 1, null, true);
6.System.out.println(p1.equals(p2));
7.}
8.}

Rsultat :

1.false

Logiquement, on pourrait esprer que ce test renvoie true mais pour cela il faut redfinir la mthode
equals().

97.2.2.2. La redfinition de la mthode equals()


La redfinition de la mthode equals est un besoin frquent mais il n'est pas toujours facile d'crire une
implmentation correcte qui tienne compte de la smantique de la classe.
La mthode equals() permet de vrifier si l'objet qui lui est fourni en paramtre est gal l'objet sur lequel
la
mthode
est
invoque.
Sa
signature
est
la
suivante :
public boolean equals(Object obj)
L'implmentation par dfaut de cette mthode hrite de la classe Object vrifie simplement si les
rfrences des deux objets sont les mmes (this == obj). Comme la classe Object ne possde pas de
champs, c'est le seul test qu'elle peut raliser pour tester l'galit.
La redfinition de la mthode equals() permet de fournir des rgles particulires pour le test d'galit des
objets d'une classe. Dans ce cas, son implmentation utilise gnralement un test d'galit reposant sur
tout ou partie des champs de la classe qui sont pertinents pour sa discrimination.
L'implmentation de la mthode equals() est la charge du dveloppeur qui doit dfinir ce qu'est l'galit
entre deux objets de cette classe. La classe Object propose une implmentation par dfaut qui test
simplement l'galit sur les rfrences des deux objets. Comme toutes les classes hritent de la classe
Object, si leur mthode equals() n'est pas redfinie, alors deux objet sont gaux si et seulement si ces
objets ont les mmes rfrences.
Il est donc gnralement ncessaire de redfinir la mthode equals() pour lui donner un rle smantique par
rapport aux champs de la classe. Par exemple :

deux objets de type String sont gaux si les deux chanes possdent la mme squence de
caractres

deux objets de type Integer sont gaux si leur valeur est gale

Il est prfrable d'utiliser les champs qui concernent l'tat de l'objet : ceci implique gnralement de ne
pas prendre en compte les champs static et les champs transient.

L'implmentation de la mthode equals() n'est pas toujours facile et dpend de la classe. Si la classe est
immuable alors l'implmentation de la mthode equals() peut utiliser la comparaison de l'tat de l'objet avec
l'tat de l'objet fourni en paramtre.
L'implmentation de la mthode equals() pour une classe qui n'est pas immuable est plus difficile car il faut
dcider si l'galit va se faire sur tout ou partie de l'tat de l'objet ou sur l'identit de l'objet
(l'implmentation de la classe Object utilise la rfrence par exemple). Ce choix dpend de l'utilisation qui
sera faite des instances de la classe.
L'implmentation de la mthode equals() peut parfois tre complexe selon les besoins. Par exemple, la
mthode equals() de l'interface List vrifie que l'autre objet est aussi de type List, que les deux collections
possdent le mme nombre d'lments, qu'ils contiennent les mmes lments en utilisant leur mthode
equals() et que ces lments sont dans le mme ordre.

97.2.2.3. Les contraintes et quelques recommandations


L'implmentation d'une redfinition de la mthode equals() doit respecter plusieurs caractristiques :

tre rflexive : pour tout objet x, x.equals(x) doit retourner true. Un objet doit tre gal luimme

tre symtrique : pour tout objet x et y, si x.equals(y) renvoie true alors y.equals(x) doit renvoyer
true. Si un objet est gal un autre alors l'autre doit tre gal l'objet

tre transitive : pour tout objet x,y et z, si x.equals(y) renvoie true et y.equals(z) renvoie true
alors x.equals(z) doit renvoyer true. Si un premier objet est gal un second et que le second est
gal un troisime alors le premier doit tre gal au troisime

tre cohrent : pour tout objet x et y gaux, plusieurs invocations de la mthode x.equals(y), sans
modification de x ou y, renvoient de faon consistante la mme valeur

ne jamais tre gal null : pour tout objet x non null, x.equals(null) doit toujours renvoyer false

pour respecter les spcifications, l'implmentation de la mthode equals() doit tre en relation
avec celle de la mthode hashCode() pour garantir que deux objets gaux renvoient le mme hash
code. Cependant, l'inverse n'est pas obligatoirement vrai

Le non respect des rgles qui dfinissent le contrat de la mthode equals() peut induire des bugs difficiles
identifier car ce sont des problmes de conception.
Il n'existe pas de solution unique pour redfinir la mthode equals() tant que les contraintes imposes par la
spcification sont respectes. La plupart des IDE propose mme une fonctionnalit pour gnrer cette
mthode partir de tout ou partie des champs de la classe.
Exemple :

01.import java.util.Date;
02.
03.public class Personne {
04.
05.private String nom;
06.private String prenom;

07.private long id;


08.private Date dateNaiss;
09.private boolean adulte;
10.
11.public Personne(String nom, String prenom, long id, Date dateNaiss,
12.boolean adulte) {
13.super();
14.this.nom = nom;
15.this.prenom = prenom;
16.this.id = id;
17.this.dateNaiss = dateNaiss;
18.this.adulte = adulte;
19.}
20.
21.@Override
22.public boolean equals(Object obj) {
23.if (this == obj)
24.return true;
25.if (obj == null)
26.return false;
27.if (getClass() != obj.getClass())
28.return false;
29.Personne other = (Personne) obj;
30.if (adulte != other.adulte)
31.return false;
32.if (dateNaiss == null) {
33.if (other.dateNaiss != null)
34.return false;
35.} else if (!dateNaiss.equals(other.dateNaiss))
36.return false;
37.if (id != other.id)
38.return false;
39.if (nom == null) {
40.if (other.nom != null)
41.return false;
42.} else if (!nom.equals(other.nom))
43.return false;
44.if (prenom == null) {
45.if (other.prenom != null)
46.return false;
47.} else if (!prenom.equals(other.prenom))
48.return false;
49.return true;
50.}
51.// ...
52.}

Lors de la redfinition de la mthode equals(), il faut bien faire attention respecter la signature de la
mthode qui attend en paramtre une instance de type Object sinon c'est une surcharge qui se compilera
sans soucis mais qui ne sera pas invoque pour tester l'galit.

Pour viter ce problme, il faut utiliser l'annotation @Override sur la redfinition de la mthode, assurant
ainsi une erreur la compilation si la mthode n'est pas une redfinition d'une mthode hrite.
La redfinition de la mthode equals() n'est pas obligatoire et n'est pas toujours forcement ncessaire
notamment :

si le test de l'galit avec d'autres objets n'est pas ncessaire

si l'implmentation par dfaut hrite de la classe Object est suffisante

si chaque instance de la classe est unique ou s'il n'existe qu'une seule instance de la classe
(singleton)

si l'implmentation hrite de la classe mre est suffisante : il est cependant ncessaire de


s'assurer que cela soit bien le cas

Si le test de l'galit d'une classe n'a pas de sens, il est prfrable de redfinir la mthode equals() pour
qu'elle lve une exception de type UnsupportedOperationException. Ceci permet d'viter d'avoir le
comportement d'une des classes mre, qui peut tre celui de la classe Object.
La mthode equals() est frquemment utilise notamment dans la plupart des implmentations de collections
pour savoir si un objet est dj prsent dans la collection ou non. Il est donc important que la redfinition
de la mthode equals() soit optimise et efficace surtout si le nombre d'instances dans la collection est
important.
Pour optimiser ces performances, il est par exemple possible de suivre quelques recommandations :

pour assurer la contrainte symtrique, un des premiers test de la redfinition de la mthode


equals() devrait tre de tester l'galit de l'instance avec celle fournie en paramtre de la
mthode car il est inutile de faire d'autres tests si c'est la mme instance

il faut rapidement tester si l'instance passe en paramtre est null pour renvoyer directement
false

comme l'instance fournie en paramtre est de type Object, il faut tester si la classe de l'instance
courante est identique la classe de l'objet fourni en paramtre de la mthode ou si celui-ci est
une instance de la classe courante : si ce n'est pas le cas, il faut renvoyer directement false sinon il
est possible de caster le paramtre dans le type de la classe courante pour permettre des tests
sur les valeurs des champs

il peut tre intressant de faire les comparaisons des valeurs des champs les plus rapides en
premier comme par les champs de type int. Si la valeur est diffrente, il n'est pas ncessaire de
tester les valeurs des autres champs

Par contrat, la mthode equals() attend un objet de type Object : il est donc prfrable avant de tester
l'galit des membres de la classe de s'assurer de l'galit du type de la classe avec celui de celle fournie
en paramtre.
Il y a deux manires de vrifier l'galit de la classe avant de vrifier l'galit des membres :

utiliser l'oprateur instanceof

utiliser la mthode equals() sur les classes des deux objets obtenues en invoquant leur mthode
getClass()

Chacune de ces solutions a son utilit selon les circonstances et l'utilisation de l'une ou l'autre dpend des
besoins.
Il est gnralement prfrable de tester que les objets soient du mme type en testant l'galit de
l'invocation de leur mthode getClass(). Ce test permet de renvoyer false si l'instance fournie en paramtre
est une sous-classe de l'instance courante. Ce type de test n'est pas obligatoire mais dans ce cas, les
classes qui peuvent tre passes en paramtre de la mthode equals() doivent faire de mme pour respecter
la rgle de symtrie et de rflexivit.
Cependant, pour certains cas particuliers, il peut tre souhaitable de tester que les objets soient du mme
type en utilisant l'oprateur instanceof. Un exemple de cas particulier concerne les entits utilises avec
Hibernate : comme ce dernier peut crer des proxys, il est prfrable d'utiliser l'oprateur instanceof.
Attention cependant, ce n'est gnralement pas une bonne ide d'utiliser l'oprateur instanceof lorsque la
mthode equals() doit tre redfinie car gnralement cela peut violer la rgle de symtrie que doit
respecter l'implmentation de la mthode equals().
Le test sur l'galit des classes des deux instances permet de pouvoir tendre la classe sans avoir
redfinir la mthode equals() pour respecter la rgle concernant la symtrie.

97.2.3. La mthode hashCode()


La mthode hashCode() retourne valeur de hachage calcule sur l'instance d'un objet.
La valeur du hash code est essentiellement utilise par les collections de type Hashxxx (java.util.Hashtable,
java.util.HashMap, java.util.HashSet et leurs sous-classes, ...) qui utilisent la valeur de hachage pour
amliorer leur performance.
La valeur de hachage peut galement tre utilise dans un autre contexte que celui des collections : par
exemple, pour amliorer les performances en Java SE 7, le compilateur transforme les instructions switch
utilisant des chanes de caractres en une srie d'instructions if qui testent d'abord la valeur de hash.
La dfinition de la mthode hashCode() dans la classe Object possde la signature suivante :
Exemple :

1.public native int hashCode();

Cette mthode est dclare native car c'est l'implmentation de la JVM qui peut obtenir l'adresse mmoire
de l'objet. Par dfaut, la mthode hashCode(), dfinie dans la classe Object, utilise l'adresse mmoire de
l'instance pour crer la valeur de type int du hashcode de l'instance.
Il est cependant possible de redfinir cette mthode puisque toutes les classes hritent de la classe
Object.

97.2.3.1. L'implmentation par dfaut


La classe Object propose une implmentation par dfaut de la mthode hashCode() qui renvoie la rfrence
de l'objet sous la forme d'une valeur de type int. Il est possible sur certaines plate-formes que la valeur de
la rfrence soit suprieure la capacit d'un entier de type int : c'est pour cette raison que deux objets
distincts peuvent avoir le mme hashcode.
Si la mthode hashCode() est redfinie, il est possible d'obtenir la valeur du hashcode par dfaut telle
qu'elle serait renvoye par l'implmentation de la mthode hashCode() fournie par la classe Object en
utilisant la mthode System.identityHashCode().
Exemple :

01.public class TestHashcode {


02.
03.public static void main(String[] args) {
04.String chaine = "ma chaine";
05.System.out.println("chaine.hashCode() = " + chaine.hashCode());
06.int identityHashcode = System.identityHashCode(chaine);
07.System.out.println("chaine identityHashcode = " + identityHashcode);
08.Object monObjet = new Object();
09.System.out.println("monObjet.hashCode() = " + monObjet.hashCode());
10.identityHashcode = System.identityHashCode(monObjet);
11.System.out.println("monObjet identityHashcode = " + identityHashcode);
12.}
13.}

Rsultat :

1.chaine.hashCode() = -921457200
2.chaine identityHashcode = 4072869
3.monObjet.hashCode() = 1671711
4.monObjet identityHashcode = 1671711

97.2.3.2. La redfinition de la mthode hashCode()


Comme prcis pour la mthode equals() de la classe Object dans la Javadoc, il est ncessaire de redfinir
la mthode hashCode() si la mthode equals() est redfinie car il faut respecter le contrat qui prcise que
deux objets gaux doivent avoir le mme hashcode.
Gnralement, la redfinition de la mthode equals() utilise tout ou partie des attributs de la classe pour
tester l'galit de deux objets. Il est gnralement pratique d'utiliser les mmes attributs dans le calcul
du hashcode afin de garantir que deux objets gaux ont le mme hashcode.
La problmatique est que la valeur de retour de la mthode hashCode() est de type int : il est donc
ncessaire d'appliquer un algorithme qui va dterminer une valeur de type int partir des champs utiliser.
Il est ncessaire que cet algorithme assure que la valeur de hachage calcule soit toujours la mme avec les
mmes attributs. Gnralement, cet algorithme calcule une valeur de type int pour chaque attributs et

combine ces valeurs en utilisant un multiplicateur (gnralement un nombre premier) pour dterminer la
valeur de hachage.
Il n'existe pas de solution unique pour redfinir la mthode hashCode() tant que les contraintes imposes
par la spcification sont respectes.
Exemple :

01.import java.util.Date;
02.
03.public class Personne {
04.
05.private String nom;
06.private String prenom;
07.private long id;
08.private Date dateNaiss;
09.private boolean adulte;
10.
11.@Override
12.public int hashCode() {
13.final int prime = 31;
14.int result = 1;
15.result = prime * result
16.result = prime * result
dateNaiss.hashCode());
17.result = prime * result
18.result = prime * result
19.result = prime * result
20.return result;
21.}
22.}

+ (adulte ? 1231 : 1237);


+ ((dateNaiss == null) ? 0 :
+ (int) (id ^ (id >>> 32));
+ ((nom == null) ? 0 : nom.hashCode());
+ ((prenom == null) ? 0 : prenom.hashCode());

97.2.3.3. Les contraintes et les recommandations


La redfinition de la mthode hashCode() doit explicitement respecter plusieurs rgles :

la valeur renvoye doit tre constante lors de plusieurs invocations sur un mme objet durant la
dure de vie de l'application. Cette valeur n'a pas d'obligation d'tre constante sur plusieurs
excutions de l'application

deux objets gaux (l'invocation de la mthode equals() sur une instance avec l'autre en paramtre
renvoie true) doivent obligatoirement avoir le mme hash code

si deux objets ne sont pas gaux en invoquant la mthode equals(), alors l'invocation de la mthode
hashCode() de chacun des objets n'a pas l'obligation de renvoyer des valeurs entires diffrentes

plus la dispersion des valeurs de hachage calcules est importante, meilleures seront les
performances lorsque l'objet sera utilis comme dans une collection de type HashXXX

L'implmentation par dfaut de la mthode hashCode(), hrite de la classe Object et qui utilise la
rfrence de l'objet, respecte ces rgles :

la rfrence de l'objet de change pas durant la mme excution de l'application

par dfaut, la mthode equals() vrifie l'galit des rfrences des deux objets : donc deux objets
gaux renverront la mme valeur de hachage

Deux objets gaux doivent avoir la mme valeur de hachage tant qu'ils restent gaux mais deux objets non
gaux n'ont pas l'obligation d'avoir des valeurs de hachage distinctes. Pour respecter ces deux rgles, il est
ncessaire de redfinir la mthode hashCode() lorsque la mthode equals() est redfinie.
De plus, par dfaut, la mthode hashCode() renvoie la valeur de type int dtermine partir de l'adresse
mmoire de l'instance. Cela permet d'avoir une bonne rpartition des valeurs retournes par la mthode
hashCode() mais ne permet pas de retourner la mme valeur pour deux instances dont la mthode equals()
est redfinie pour tester l'galit des valeurs de leur proprit. Il faut donc redfinir la mthode
hashCode() en consquence si la mthode equals() est redfinie et assurer ainsi une cohrence entre leurs
implmentations.
La faon la plus simple de garantir que deux objets gaux possdent la mme valeur de hachage est
d'utiliser les mmes attributs de la classe dans l'implmentation des mthodes equals() et hashCode().
La redfinition de la mthode hashCode() doit viter au maximum de renvoyer la mme valeur pour deux
instances mme si cela est quasi impossible puisque les valeurs possibles sont celles du type int du hashcode
et qu'elles doivent tre calcules le plus rapidement possible.
Le simple fait que l'implmentation de la mthode hashCode() renvoie une valeur fixe pour toutes les
instances est une implmentation qui respecte les rgles : deux objets gaux auront forcment le mme
hashcode et la valeur du hashcode d'un objet sera obligatoirement consistante lors de plusieurs invocations
de la mthode hashCode(). Cependant, cette implmentation implique de trs mauvaises performances lors
de l'utilisation dans des collections de type HashXXX.
La valeur de hachage des diffrents objets doit tre assez significative et reprsentative dans la plage des
valeurs permises par un entier de type int. Pour atteindre cet objectif, quelques rgles peuvent tre
utilises :

initialiser la valeur de retour avec un entier premier

utiliser une formule mathmatique ddie pour chaque type primitif pour dterminer une valeur
entire : deux nombres premiers pour les boolens, dcalage de bits pour les types plus grands
qu'un entier, ...

faire des combinaisons en ajoutant la valeur de chaque attribut multiplie par un nombre premier

Une implmentation de la mthode hashCode() utilise donc frquemment un ou deux nombres premiers et
une expression mathmatique dans l'algorithme de calcul. Gnralement, l'algorithme utilise une
combinaison des valeurs de hachage des diffrents attributs qui composent la classe.
Il n'est pas forcement ncessaire d'utiliser tous les attributs mais il faut dans ce cas slectionner les
attributs qui permettront d'tre le plus discriminant. Il faut cependant garantir le respect de la rgle de
cohrence entre la mthode hashCode() et equals().

Les spcifications n'imposent aucun algorithme pour l'implmentation de la mthode hashCode() de la classe
Object. Il n'est donc pas possible de se baser sur la valeur de hachage par dfaut entre deux JVM de deux
fournisseurs.
Il est trs important d'optimiser le calcul de la valeur retourne par la mthode hashCode().
Ainsi si le calcul de la valeur du hashcode est complexe ou pour amliorer les performances, il est possible
de mettre en cache la valeur de hachage calcule. Deux cas de figure sont prendre en compte :

l'objet est immuable : dans ce cas, c'est trs facile car le hashcode peut tre calcul une seule et
unique fois lorsque l'objet est initialis

l'objet n'est pas immuable : il est alors ncessaire de recalculer la valeur du hashcode stock
chaque modification de la valeur d'un attribut. Il faut cependant dans ce cas avoir la maitrise de
tous les cas o la valeur d'un attribut peut tre modifie afin d'tre en mesure de recalculer la
nouvelle valeur de hachage

Le stockage de la valeur de hachage est donc une solution utilisable sans soucis pour un objet immuable.
Exemple :

01.import java.util.Date;
02.
03.public class PersonneImmuable {
04.private final String nom;
05.private final String prenom;
06.private final long id;
07.private final Date dateNaiss;
08.private final boolean adulte;
09.private final int cacheHashCode;
10.
11.public PersonneImmuable(String nom, String prenom, long id, Date
dateNaiss,
12.boolean adulte) {
13.super();
14.this.nom = nom;
15.this.prenom = prenom;
16.this.id = id;
17.this.dateNaiss = dateNaiss;
18.this.adulte = adulte;
19.this.cacheHashCode = calculerHashCode();
20.}
21.
22.@Override
23.public int hashCode() {
24.return cacheHashCode;
25.}
26.
27.private int calculerHashCode() {
28.final int prime = 31;
29.int result = 1;
30.result = prime * result + (adulte ? 1231 : 1237);
31.result = prime * result + ((dateNaiss == null) ? 0 :
dateNaiss.hashCode());

32.result = prime * result + (int) (id ^ (id >>> 32));


33.result = prime * result + ((nom == null) ? 0 : nom.hashCode());
34.result = prime * result + ((prenom == null) ? 0 : prenom.hashCode());
35.return result;
36.}
37.
38.@Override
39.public boolean equals(Object obj) {
40.if (this == obj)
41.return true;
42.if (obj == null)
43.return false;
44.if (getClass() != obj.getClass())
45.return false;
46.PersonneImmuable other = (PersonneImmuable) obj;
47.if (hashCode() != other.hashCode()) {
48.return false;
49.}
50.if (adulte != other.adulte)
51.return false;
52.if (dateNaiss == null) {
53.if (other.dateNaiss != null)
54.return false;
55.} else if (!dateNaiss.equals(other.dateNaiss))
56.return false;
57.if (id != other.id)
58.return false;
59.if (nom == null) {
60.if (other.nom != null)
61.return false;
62.} else if (!nom.equals(other.nom))
63.return false;
64.if (prenom == null) {
65.if (other.prenom != null)
66.return false;
67.} else if (!prenom.equals(other.prenom))
68.return false;
69.return true;
70.}
71.
72.// ...
73.}

La valeur de hachage mise en cache peut tre utilise pour optimiser l'algorithme de la mthode equals() : si
la valeur de hachage est diffrente alors les objets ne sont pas gaux. Attention cependant, l'inverse n'est
pas vrai : si les valeurs de hachage sont gales alors les objets ne sont peut tre pas gaux.
Pour une classe qui n'est pas immuable, la mise en cache de la valeur de hash est beaucoup moins triviale car
la valeur doit tre recalcule chaque fois que la valeur d'un attribut qui entre dans le calcul de la valeur de
hachage est modifie.

La mise en cache de la valeur de hachage n'est peut tre pas une bonne ide si le nombre d'instances est
trs important car cela risque d'occuper beaucoup de place dans le heap.

Vous aimerez peut-être aussi