Comment les .equals et .hashCode par défaut fonctionneront-ils pour mes classes?

106

Dis que j'ai ma propre classe

public class MyObj { /* ... */ }

Il a quelques attributs et méthodes. Il N'implémente PAS equals, N'implémente PAS hashCode.

Une fois que nous appelons equals et hashCode, quelles sont les implémentations par défaut? De la classe Object? Et que sont-ils? Comment la valeur par défaut fonctionnera-t-elle? Comment fonctionnera le hashCode par défaut et que retournera-t-il? == vérifiera simplement s'ils font référence au même objet, donc c'est facile, mais qu'en est-il des méthodes equals () et hashCode ()?

alexeypro
la source

Réponses:

94

Oui, l'implémentation par défaut est celle d'Object (en général, si vous héritez d'une classe qui a redéfini equals et / ou hashCode, vous utiliserez cette implémentation à la place).

De la documentation:

equals

La méthode equals pour la classe Object implémente la relation d'équivalence la plus discriminante possible sur les objets; autrement dit, pour toutes les valeurs de référence non nulles x et y, cette méthode renvoie true si et seulement si x et y font référence au même objet (x == y a la valeur true).

hashCode

Autant que cela soit raisonnablement pratique, la méthode hashCode définie par la classe Object renvoie des entiers distincts pour des objets distincts. (Ceci est généralement implémenté en convertissant l'adresse interne de l'objet en un entier, mais cette technique d'implémentation n'est pas requise par le langage de programmation JavaTM.)

Etienne de Martel
la source
50

Depuis l' Objectune des implémentations JVM:

public boolean equals(Object object) {
    return this == object;
}

public int hashCode() {
    return VMMemoryManager.getIdentityHashCode(this);
}

Dans les deux cas, il s'agit simplement de comparer les adresses mémoire des objets en question.

Brad Mace
la source
7
De quelle version de JDK provient-il? Dans v6u23 ea:public native int hashCode();
khachik
@kha - Vous avez raison, je pense que j'ai retrouvé l'une des implémentations natives pour voir ce qu'elle a réellement fait
Brad Mace
10

Il existe des implémentations par défaut de equals()et hashCode()dans Object. Si vous ne fournissez pas votre propre implémentation, celles-ci seront utilisées. Car equals(), cela signifie une ==comparaison: les objets ne seront égaux que s'ils sont exactement le même objet. Pour hashCode(), le Javadoc a une bonne explication.

Pour plus d'informations, voir Effective Java, Chapitre 3 (pdf), élément 8.

Jorn
la source
1

Oui, de la Objectclasse puisque votre classe étend Object implicitement. equalsretourne simplement this == obj. hashCodela mise en œuvre est native. Juste une supposition - il renvoie le pointeur vers l'objet.

Khachik
la source
2
C'est un pointeur vers l'objet situé en mémoire, mais ce n'est pas une adresse mémoire de l'objet. Le GC peut déplacer l'objet en mémoire et le code de hachage restera le même.
Jeremy
@Jeremy Merci. stackoverflow.com/questions/2427631/… peut être intéressant.
khachik
1

Si vous ne fournissez pas votre propre implémentation, celle dérivée d'Object sera utilisée. C'est OK, sauf si vous prévoyez de mettre vos instances de classe dans ie HashSet (toute collection qui utilise réellement hashCode ()), ou quelque chose qui a besoin de vérifier l'égalité de l'objet (c'est-à-dire la méthode contains () de HashSet). Sinon, cela ne fonctionnera pas correctement, si c'est ce que vous demandez.

Il est assez facile de fournir votre propre implémentation de ces méthodes grâce à HashCodeBuilder et EqualsBuilder d' Apache Commons Lang .

Paweł Dyda
la source
(a) Pourquoi dites-vous que l'implémentation par défaut de la classe Object 'equals' ne fonctionnera pas correctement avec HashSet? Cela contredit les autres réponses sur cette page. (b) Merci pour les liens de Commons Lang.
Basil Bourque
1
@Basil: Je ne pense pas que cela contredit. Bien sûr, l'implémentation par défaut fonctionnerait ... d'une manière ou d'une autre, mais pas comme vous le souhaitez. Autrement dit, puisque equals () utilise l'égalité de référence, deux objets autrement identiques seraient "différents" aux yeux de l'implémentation par défaut. En conséquence, vous pourriez finir par avoir deux instances différentes de la même chose exactement dans votre ensemble. Et l'utilisation plutôt typique des sets est lorsque vous voulez éliminer les doublons ...
Paweł Dyda
@ PawełDyda: Le comportement par défaut est généralement correct pour les types mutables. Si Fooet Barsont des références à deux instances différentes d'un type mutable, et qu'il existe une méthode (par exemple SomeMutatingMethod) qui Foo.SomeMutatingMethod()n'affecte pas de Barla même manière qu'elle le fait Foo, cette différence devrait être suffisante pour considérer les objets comme inégaux.
supercat
0

IBM DeveloperWorks dit:

Dans cette implémentation par défaut, deux références sont égales uniquement si elles se réfèrent exactement au même objet. De même, l'implémentation par défaut de hashCode () fournie par Object est dérivée en mappant l'adresse mémoire de l'objet à une valeur entière.

Cependant, pour être sûr des détails d'implémentation exacts pour la version Java d'un fournisseur particulier, il est probablement préférable de rechercher la source (si elle est disponible)

brabster
la source