Wie funktionieren standardmäßig .equals und .hashCode für meine Klassen?

106

Angenommen, ich habe meine eigene Klasse

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

Es hat einige Attribute und Methoden. Es implementiert NICHT gleich, implementiert NICHT hashCode.

Was sind die Standardimplementierungen, wenn wir equals und hashCode aufrufen? Aus der Objektklasse? Und was sind sie? Wie funktioniert die Standardeinstellung? Wie funktioniert der Standard-Hashcode und was wird zurückgegeben? == prüft nur, ob sie auf dasselbe Objekt verweisen, also ist es einfach, aber was ist mit den Methoden equals () und hashCode ()?

alexeypro
quelle

Antworten:

94

Ja, die Standardimplementierung ist die von Object (im Allgemeinen; wenn Sie von einer Klasse erben, die equals und / oder hashCode neu definiert hat, verwenden Sie stattdessen diese Implementierung).

Aus der Dokumentation:

equals

Die Methode equals für die Klasse Object implementiert die bestmögliche Äquivalenzbeziehung für Objekte. Das heißt, für alle Nicht-Null-Referenzwerte x und y gibt diese Methode genau dann true zurück, wenn x und y auf dasselbe Objekt verweisen (x == y hat den Wert true).

hashCode

Soweit dies vernünftigerweise praktikabel ist, gibt die von class Object definierte hashCode-Methode unterschiedliche Ganzzahlen für unterschiedliche Objekte zurück. (Dies wird normalerweise implementiert, indem die interne Adresse des Objekts in eine Ganzzahl konvertiert wird. Diese Implementierungstechnik wird jedoch von der JavaTM-Programmiersprache nicht benötigt.)

Etienne de Martel
quelle
50

Von Objectin einer der JVM-Implementierungen:

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

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

In beiden Fällen werden lediglich die Speicheradressen der betreffenden Objekte verglichen.

Brad Mace
quelle
7
Aus welcher Version von JDK stammt es? In v6u23 ea:public native int hashCode();
Khachik
@kha - Sie haben Recht, ich glaube, ich habe eine der nativen Implementierungen aufgespürt, um zu sehen, was sie tatsächlich getan hat
Brad Mace
10

Es gibt Standardimplementierungen von equals()und hashCode()in Object. Wenn Sie keine eigene Implementierung bereitstellen, werden diese verwendet. Für equals()bedeutet dies einen ==Vergleich: Die Objekte sind nur dann gleich, wenn sie genau dasselbe Objekt sind. Denn hashCode()der Javadoc hat eine gute Erklärung.

Weitere Informationen finden Sie unter Effektives Java, Kapitel 3 (pdf), Punkt 8.

Jorn
quelle
1

Ja, aus der ObjectKlasse, da Ihre Klasse Object implizit erweitert. equalskehrt einfach zurück this == obj. hashCodeImplementierung ist nativ. Nur eine Vermutung - es gibt den Zeiger auf das Objekt zurück.

Khachik
quelle
2
Es ist ein Zeiger auf das Objekt im Speicher, aber keine Speicheradresse des Objekts. Der GC kann das Objekt im Speicher verschieben und der Hash-Code bleibt gleich.
Jeremy
@ Jeremy Danke. stackoverflow.com/questions/2427631/… kann interessant sein.
Khachik
1

Wenn Sie keine eigene Implementierung bereitstellen, wird eine von Object abgeleitete verwendet. Dies ist in Ordnung, es sei denn, Sie planen, Ihre Klasseninstanzen in HashSet (eine Sammlung, die tatsächlich hashCode () verwendet) oder in etwas, das die Gleichheit des Objekts überprüfen muss (dh die Methode includes () von HashSet), abzulegen. Andernfalls funktioniert es nicht richtig, wenn Sie danach fragen.

Dank HashCodeBuilder und EqualsBuilder von Apache Commons Lang ist es recht einfach, diese Methoden selbst zu implementieren .

Paweł Dyda
quelle
(a) Warum funktioniert die Standardimplementierung von 'equals' der Objektklasse mit HashSet nicht richtig? Das widerspricht den anderen Antworten auf dieser Seite. (b) Danke für die Commons Lang Links.
Basil Bourque
1
@Basil: Ich denke nicht, dass das widerspricht. Natürlich würde die Standardimplementierung funktionieren ... irgendwie, aber nicht so, wie Sie es erwarten. Das heißt, da equals () Referenzgleichheit verwendet, wären zwei ansonsten identische Objekte in den Augen der Standardimplementierung "unterschiedlich". Infolgedessen haben Sie möglicherweise zwei verschiedene Instanzen genau derselben Sache in Ihrem Set. Und eher typische Verwendung von Sets ist, wenn Sie Duplikate beseitigen möchten ...
Paweł Dyda
@ PawełDyda: Das Standardverhalten ist im Allgemeinen für veränderbare Typen korrekt. Wenn Foound BarVerweise auf zwei verschiedene Instanzen eines veränderlichen Typs sind und es eine Methode gibt (z. B. SomeMutatingMethod), die Foo.SomeMutatingMethod()sich nicht auf Bardie gleiche Weise auswirkt Foo, sollte dieser Unterschied ausreichen, um die Objekte als ungleich anzusehen.
Supercat
0

IBMs Developerworks sagt:

Bei dieser Standardimplementierung sind zwei Referenzen nur dann gleich, wenn sie sich auf genau dasselbe Objekt beziehen. In ähnlicher Weise wird die von Object bereitgestellte Standardimplementierung von hashCode () abgeleitet, indem die Speicheradresse des Objekts einem ganzzahligen Wert zugeordnet wird.

Um jedoch die genauen Implementierungsdetails für die Java-Version eines bestimmten Anbieters zu ermitteln, ist es wahrscheinlich am besten, als Quelle zu suchen (sofern verfügbar).

Brabster
quelle