Welche Themen sollten betrachtet werden, wenn Sie das überschreiben von equals und hashCode in Java?
Welche Probleme /Fallstricke berücksichtigt werden müssen, wenn das überschreiben equals
und hashCode
?
InformationsquelleAutor Matt Sheppard | 2008-08-26
Du musst angemeldet sein, um einen Kommentar abzugeben.
Die Theorie (für die Sprache der Juristen und der mathematisch):
equals()
(javadoc) definieren eine äquivalenz-relation (es muss reflexive, symmetrischen, und transitive). Zusätzlich, Sie werden müssen konsistente (sofern die Objekte nicht verändert wird, dann muss es immer wieder der gleiche Wert). Darüber hinauso.equals(null)
muss immer false zurück.hashCode()
(javadoc) müssen auch konsistente (wenn das Objekt nicht geändert in Bezug aufequals()
es müssen immer wieder die gleichen Wert).Den Bezug zwischen den beiden Methoden ist:
In der Praxis:
Wenn Sie überschreiben, dann sollten Sie überschreiben die anderen.
Verwenden den gleichen Satz von Feldern, die Sie verwenden, um zu berechnen
equals()
zu berechnenhashCode()
.Nutzen die hervorragende Helfer-Klassen EqualsBuilder und HashCodeBuilder aus der Apache Commons Lang Bibliothek. Ein Beispiel:
Denken Sie auch daran:
Wenn eine hash-basierte Sammlung oder Anzeigen wie HashSet, LinkedHashSet, HashMap, Hashtable, oder WeakHashMap, stellen Sie sicher, dass die hashCode() der key-Objekte, die Sie in der Sammlung, die sich nie ändert, während das Objekt in der Sammlung. Der kugelsichere Weg, um sicherzustellen, dass dies, um Ihren Schlüssel unveränderlich, das hat auch andere Vorteile.
Erhalten Sie Eclipse zu erzeugen, die zwei Methoden für Sie: Quelle > Generate hashCode() und equals().
Gleiche gilt für die Netbeans: developmentality.wordpress.com/2010/08/24/...
Eclipse generierten equals verwendet getClass (), die möglicherweise Probleme verursachen, in einigen Fällen (siehe Effektive Java-posten 8)
Die erste null-check ist nicht notwendig, angesichts der Tatsache, dass
instanceof
gibt false zurück, wenn die erste operand null ist (Effective Java).InformationsquelleAutor
Gibt es einige Punkte, die es Wert zu bemerken, wenn Sie den Umgang mit Klassen, die persistent gespeichert werden mit einem Objekt-Beziehung-Mapper (ORM) wie Ruhezustand, wenn Sie nicht denken, das war unangemessen kompliziert schon!
Faul geladenen Objekte sind Unterklassen
Wenn Ihr Objekte sind persistent, mit einem ORM, in vielen Fällen werden Sie den Umgang mit dynamischen proxies zu vermeiden, laden-Objekt zu früh aus dem datenspeicher. Diese proxies implementiert werden als Unterklassen von Ihrer eigenen Klasse. Dies bedeutet, dass
this.getClass() == o.getClass()
zurückfalse
. Zum Beispiel:Wenn man sich mit einem ORM, mit
o instanceof Person
ist die einzige Sache, die sich korrekt Verhalten.Lazy geladene Objekte haben null-Felder
ORMs in der Regel mit dem Getter zu erzwingen faul geladenen Objekte. Dies bedeutet, dass
person.name
wirdnull
wennperson
faul ist geladen, auch wennperson.getName()
Kräfte be-und Versandkosten "John Doe". In meiner Erfahrung, dies tritt öfter bei derhashCode()
undequals()
.Wenn man sich mit ein ORM, stellen Sie sicher, dass Sie immer Getter und nie Feld-Referenzen in
hashCode()
undequals()
.Speichern ein Objekt ändert seinen Zustand
Persistente Objekte verwenden oft eine
id
Feld zu halten, den Schlüssel des Objekts. Dieses Feld wird automatisch aktualisiert, wenn ein Objekt wird zunächst gespeichert. Verwenden Sie nicht ein id-Feld inhashCode()
. Aber Sie können es verwenden, inequals()
.Einem Muster, das ich oft benutze, ist
Aber: Sie können nicht zählen
getId()
imhashCode()
. Wenn Sie dies tun, wenn ein Objekt persistent ist, seinehashCode
änderungen. Wenn sich das Objekt in einemHashSet
, Sie werde "nie" wieder finden.In meinem
Person
Beispiel, ich wahrscheinlich verwenden würdegetName()
fürhashCode
undgetId()
plusgetName()
(nur für paranoia) fürequals()
. Es ist okay, wenn es eine gewisse Gefahr von "Kollisionen" fürhashCode()
, aber nie okay fürequals()
.hashCode()
sollte die nicht-ändern Teilmenge der Eigenschaften vonequals()
Saving an object will change it's state
!hashCode
muss zurückint
, so wie SiegetName()
? Können Sie ein Beispiel geben für IhrehashCode
getName liefert eine String-Objekt, das hat auch einen hashCode, die verwendet werden können
InformationsquelleAutor Johannes Brodwall
Einer Klärung über die
obj.getClass() != getClass()
.Diese Aussage ist das Ergebnis von
equals()
sein Erbe unfreundlich. Die JLS (Java language specification) legt fest, dass, wennA.equals(B) == true
dannB.equals(A)
muss auch zurücktrue
. Wenn Sie die weglassen, die Aussage erbenden Klassen überschreibenequals()
(und ändern Ihr Verhalten) brechen dieser Spezifikation.Betrachten Sie das folgende Beispiel, was passiert, wenn die Anweisung weggelassen wird:
Tun
new A(1).equals(new A(1))
Auchnew B(1,1).equals(new B(1,1))
Resultat heraus wahr, wie es sollte.Das sieht alles sehr gut aus, aber schauen Sie, was passiert, wenn wir versuchen, beide Klassen:
Offensichtlich ist dies falsch.
Wenn Sie sicherstellen möchten, dass die symmetrischen Zustand. a=b wenn b=a ist und das Liskov-substitution-Prinzip nennen
super.equals(other)
nicht nur im Fall vonB
Instanz, sondern prüfen Sie nach fürA
Beispiel:Die Ausgabe:
Wo, wenn
a
ist nicht eine ReferenzB
, dann könnte es sein, eine Referenz der KlasseA
(weil Sie es verlängern), in diesem Fall rufen Siesuper.equals()
zu.dann würd ich bekomme eine stackoverflow, wenn die Implementierung der Klasse nicht überschreiben der equals-Methode. nicht aus Spaß.
Sie werden nicht einen stackoverflow. Wenn die equals-Methode nicht überschrieben wird, die Sie anrufen, den gleichen code wieder, aber die Bedingung für die Rekursion wird immer falsch sein!
Wie muss man sich Verhalten, wenn es zwei verschiedene abgeleitete Klassen? Wenn ein
ThingWithOptionSetA
können gleich zu einemThing
vorausgesetzt, dass alle extra-Optionen haben Standardwerte, und ebenfalls für eineThingWithOptionSetB
, dann sollte es möglich sein, für eineThingWithOptionSetA
zu vergleichen, die gleich einemThingWithOptionSetB
nur, wenn alle non-base-Eigenschaften beider Objekte übereinstimmen Ihre Standardwerte zurückgesetzt, aber ich sehe nicht, wie Sie testen.Das problem mit diesem ist es, dass es Pausen Transitivität. Wenn Sie hinzufügen
B b2 = new B(1,99)
, dannb.equals(a) == true
unda.equals(b2) == true
aberb.equals(b2) == false
.InformationsquelleAutor Ran Biron
Für eine erbschaft-freundliche Umsetzung, check-out-Tal Cohen ' s Lösung, Wie melde ich mich Richtig Implementieren Sie die equals () - Methode?
Zusammenfassung:
In seinem Buch Effektive Java-Programming Language Guide (Addison-Wesley, 2001), Joshua Bloch behauptet, dass "Es gibt einfach keine Möglichkeit zum erweitern einer instanziierbaren Klasse und füge einen Aspekt, während die Erhaltung der equals-Vertrag." Tal widerspricht.
Seine Lösung ist die Implementierung von equals() durch den Aufruf einer anderen nonsymmetric blindlyEquals() beide Möglichkeiten. blindlyEquals() von Unterklassen überschrieben equals() wird vererbt, und nie außer Kraft gesetzt.
Beispiel:
Beachten Sie, dass equals() muss die Arbeit über die Vererbung von Hierarchien wenn Sie die Liskov-Substitution-Prinzip ist, zufrieden zu sein.
Punkt.equals() sollte die o gegossen, um einen Punkt (es ist zu versuchen, rufen Sie blindlyEquals() auf einem Objekt). Aber das kann gewollt sein (in einem Versuch, zu betonen, die Methode).
In jedem Fall, ich glaube nicht, dass das eine gute Idee ist. Es macht die Equals-Vertrag unnötig verwirrend, jemand der sich zwei Punkt-Parametern, a und b bewusst auf die Möglichkeit, dass ein.getX() == b".getX() und ein.getY() == b".getY() kann wahr sein, aber ein.equals(b) und b ist.equals(a) beide falsch sein (wenn nur einer ein ColorPoint).
Im Grunde ist das wie
if (this.getClass() != o.getClass()) return false
, aber flexibel, es gibt nur false, wenn die abgeleitete Klasse(N) stören zu ändern entspricht. Ist das richtig?InformationsquelleAutor Kevin Wong
Immer noch erstaunt, dass keiner empfohlen der guava library.
natürlich, aber Sie sollten es vermeiden, da Oracle nicht, die öffentlichen updates mehr für Java 6 (dies war der Fall seit Februar 2013).
Ihre
this
imthis.getDate()
bedeutet nichts (anderes als Unordnung)Ihr "nicht ein" Ausdruck muss eine zusätzliche Halterung:
if (!(otherObject instanceof DateAndPattern)) {
. Vereinbaren Sie mit hernan und Steve Kuo (aber das ist eine Frage des persönlichen Geschmacks), aber +1 dennoch.InformationsquelleAutor Eugene
Gibt es zwei Methoden in der super-Klasse als java.lang.Objekt. Wir überschreiben müssen Sie benutzerdefinierte Objekt.
Gleich Objekte zu produzieren, die den gleichen hash-code, solange Sie gleich sind, jedoch ungleiche Objekte müssen nicht produzieren verschiedene hash-codes.
Wenn Sie wünschen, erhalten Sie mehr, bitte prüfen Sie diesen link als http://www.javaranch.com/journal/2002/10/equalhash.html
Dies ist ein weiteres Beispiel,
http://java67.blogspot.com/2013/04/example-of-overriding-equals-hashcode-compareTo-java-method.html
Spaß Haben! @.@
InformationsquelleAutor Luna Kong
Gibt es ein paar Möglichkeiten prüfen, um die Gleichheit der Klassen, bevor Sie Mitglied der Gleichstellung, und ich denke, beide sind nützlich, in den richtigen Umständen.
instanceof
Betreiber.this.getClass().equals(that.getClass())
.Verwende ich #1 in einem
final
equals-Implementierung oder bei der Implementierung einer Schnittstelle, das vorschreibt, dass ein Algorithmus für die equals (wie diejava.util
collection interfaces—der richtige Weg, um zu überprüfen, mit(obj instanceof Set)
oder was auch immer-Schnittstelle Sie implementieren). Es ist allgemein eine schlechte Wahl, wenn equals überschrieben werden können, denn das bricht die Symmetrie-Eigenschaft.Option #2 erlaubt die Klasse sicher länger ohne überschreiben von equals oder die Brechung der Symmetrie.
Wenn Ihre Klasse ist auch
Comparable
, dieequals
undcompareTo
Methoden sollten konstant zu. Hier eine Vorlage, die für die equals-Methode in einemComparable
Klasse:Es gibt ein problem mit diesem. Anonyme Klassen, die nicht fügen Sie alle Aspekte noch überschreiben der equals-Methode werden nicht die getClass überprüfen Sie, obwohl Sie gleich sein sollte.
Es ist mir nicht klar, dass Objekte unterschiedlicher Typen gleich sein sollte; ich denke an unterschiedliche Implementationen einer Schnittstelle als gemeinsame anonyme Klasse. Können Sie ein Beispiel geben für die Unterstützung Ihrer Prämisse?
MyClass a = new MyClass(123); MeineKlasse b = new MeineKlasse(123) { // Überschreiben einer Methode }; // ein.equals(b) ist falsch, wenn mit dieser.getClass().entspricht(das.getClass())
Recht. Wie sollte es in den meisten Fällen, vor allem, wenn eine Methode überschrieben wird, anstatt Hinzugefügt. Betrachten Sie mein Beispiel oben. Wenn es nicht
final
, und diecompareTo()
- Methode überschrieben, um die Sortierreihenfolge umzukehren, Instanzen der Unterklasse und Oberklasse sollte nicht als gleich angesehen. Wenn diese Objekte benutzt wurden, zusammen in einem Baum, Tasten, waren "gleich" nach einerinstanceof
Umsetzung könnte nicht auffindbar sein.InformationsquelleAutor erickson
Für gleich, Blick in Geheimnisse von gleich zu Gleich von Angelika Langer. Ich Liebe es sehr viel. Sie ist auch eine tolle FAQ zu Generics in Java. Ihre andere Artikel hier (nach unten scrollen zu "Core Java"), wo Sie auch weiter mit Teil 2, und "mixed-Typ-Vergleich". Viel Spaß beim Lesen!
InformationsquelleAutor Johannes Schaub - litb
equals () - Methode wird verwendet, um die Gleichheit von zwei Objekten.
als int-Wert von 10 ist immer gleich 10. Aber diese equals () - Methode wird über die Gleichheit von zwei Objekten. Wenn wir sagen, Objekt, Eigenschaften. Entscheidet über die Gleichstellung auf diese Eigenschaften betrachtet werden. Es ist nicht notwendig, dass alle Eigenschaften müssen berücksichtigt werden, um zu bestimmen, die Gleichheit und in Bezug auf die definition der Klasse und Kontext entschieden werden kann. Dann die equals () - Methode kann überschrieben werden.
sollten wir immer überschreiben Sie hashCode () - Methode, wenn wir überschreiben Sie equals () - Methode. Wenn nicht, was wird passieren? Wenn wir hashtables in unsere Anwendung, es wird nicht so verhält wie erwartet. Wie der hashCode ist die Bestimmung der Gleichheit von Werten gespeichert, es wird nicht wieder das Recht entsprechende Wert für einen Schlüssel.
Default-Implementierung gegeben ist hashCode() Methode in der Object-Klasse verwendet die interne Adresse des Objektes und wandelt diese in integer und gibt Sie zurück.
Beispiel-Code-Ausgang:
InformationsquelleAutor rohan kamat
Logisch, haben wir:
a.getClass().equals(b.getClass()) && a.equals(b)
⇒a.hashCode() == b.hashCode()
Aber nicht Umgekehrt!
InformationsquelleAutor Khaled.K
Eine gotcha, die ich gefunden habe, ist, wenn zwei Objekte enthalten Referenzen auf andere (zum Beispiel ein Eltern - /Kind-Beziehung mit eine bequeme Methode, auf die Eltern zu Holen alle Kinder).
Diese Dinge sind relativ Häufig, wenn dabei die Hibernate-mappings zum Beispiel.
Wenn Sie beide enden der Beziehung in Ihrem hashCode entspricht oder tests ist es möglich, in einer rekursiven Schleife, die endet in einer StackOverflowException.
Die einfachste Lösung ist nicht die getChildren-Sammlung in den Methoden.
equals()
. Wenn ein verrückter Wissenschaftler erstellt ein Duplikat von mir, wir wären gleichwertig. Wir wären aber nicht den gleichen Vater.Es sei denn, Ihr Vater war ein verrückter Wissenschaftler, natürlich.
InformationsquelleAutor Darren Greaves