Kürzlich habe ich dieses Developer Works-Dokument gelesen .
Das Dokument ist über die Definition hashCode()
und equals()
effektiv und richtig, aber ich nicht in der Lage bin, um herauszufinden , warum wir diese beiden Methoden außer Kraft setzen müssen.
Wie kann ich die Entscheidung treffen, diese Methoden effizient umzusetzen?
Antworten:
Joshua Bloch sagt über effektives Java
Versuchen wir es anhand eines Beispiels zu verstehen, was passieren würde, wenn wir überschreiben,
equals()
ohne es zu überschreiben,hashCode()
und versuchen, a zu verwendenMap
.Angenommen, wir haben eine Klasse wie diese und zwei Objekte von
MyClass
sind gleich, wenn sieimportantField
gleich sind (mithashCode()
undequals()
durch Eclipse erzeugt).Nur überschreiben
equals
Wenn nur
equals
überschrieben wird, wird beimmyMap.put(first,someValue)
ersten Aufruf ein Hash in einen Bucket und beim AufrufmyMap.put(second,someOtherValue)
in einen anderen Bucket gehasht (da diese einen anderen habenhashCode
). Obwohl sie gleich sind, da sie nicht zum selben Bucket hashen, kann die Karte dies nicht erkennen und beide bleiben auf der Karte.Obwohl es nicht notwendig ist, zu überschreiben,
equals()
wenn wir überschreibenhashCode()
, wollen wir sehen, was in diesem speziellen Fall passieren würde, wenn wir wissen, dass zwei Objekte vonMyClass
gleich sind, wenn sieimportantField
gleich sind, aber wir nicht überschreibenequals()
.Nur überschreiben
hashCode
Stellen Sie sich vor, Sie haben das
Wenn Sie nur überschreiben , dauert es
hashCode
beim AufrufenmyMap.put(first,someValue)
zuerst, berechnet eshashCode
und speichert es in einem bestimmten Bucket. Wenn SiemyMap.put(second,someOtherValue)
es dann aufrufen , sollte es gemäß der Kartendokumentation zuerst durch das zweite ersetzt werden, da sie gleich sind (entsprechend den Geschäftsanforderungen).Das Problem ist jedoch, dass equals nicht neu definiert wurde. Wenn also die Karte
second
durch den Bucket hasht und iteriert, um zu sehen, ob es ein Objekt gibtk
,second.equals(k)
das wahr ist, wird es keines finden, wiesecond.equals(first)
es sein wirdfalse
.Hoffe es war klar
quelle
if you think you need to override one, then you need to override both of them
ist falsch. Sie müssen überschreiben,hashCode
wenn Ihre Klasse überschreibt,equals
aber umgekehrt ist nicht wahr.equals
würde den Vertrag verletzen im javadoc von buchstabiertObject
: „Wenn zwei Objekte gleich nach dem sindequals(Object)
Verfahren, dann den AufrufhashCode
. Verfahren auf jeder der beiden Objekte müssen die gleiche ganzzahlige Ergebnis produzieren“ Sicher, nicht alle Teile aller Verträge werden in allen Codes ausgeübt, aber formal gesehen handelt es sich dennoch um einen Verstoß, und ich würde es als einen Fehler betrachten, der darauf wartet, passiert zu werden.Sammlungen wie
HashMap
undHashSet
verwenden einen Hashcode- Wert eines Objekts, um zu bestimmen, wie es in einer Sammlung gespeichert werden soll, und der Hashcode wird erneut verwendet, um das Objekt in seiner Sammlung zu lokalisieren.Das Hashing-Abrufen erfolgt in zwei Schritten:
hashCode()
)equals()
)Hier ist ein kleines Beispiel, warum wir überschreiben sollten
equals()
undhashcode()
.Stellen Sie sich eine
Employee
Klasse vor, die zwei Felder enthält: Alter und Name.Erstellen Sie nun eine Klasse, fügen Sie ein
Employee
Objekt in ein einHashSet
und testen Sie, ob dieses Objekt vorhanden ist oder nicht.Es wird Folgendes gedruckt:
Führen Sie nun die Kommentierungsmethode aus
hashcode()
, und führen Sie die folgende Ausgabe aus:Können Sie nun sehen, warum, wenn zwei Objekte als gleich betrachtet werden, auch ihre Hashcodes gleich sein müssen? Andernfalls könnten Sie das Objekt nie finden, da die Standard- Hashcode- Methode in der Klasse Object praktisch immer eine eindeutige Nummer für jedes Objekt liefert , selbst wenn die
equals()
Methode so überschrieben wird, dass zwei oder mehr Objekte als gleich angesehen werden . Es spielt keine Rolle, wie gleich die Objekte sind, wenn ihre Hashcodes dies nicht widerspiegeln. Also noch einmal: Wenn zwei Objekte gleich sind, müssen auch ihre Hashcodes gleich sein.quelle
Durch die Definition
equals()
undhashCode()
Konsistenz können Sie die Benutzerfreundlichkeit Ihrer Klassen als Schlüssel in Hash-basierten Sammlungen verbessern. Wie das API-Dokument für hashCode erklärt: "Diese Methode wird zugunsten von Hashtabellen wie den von unterstütztjava.util.Hashtable
."Die beste Antwort auf Ihre Frage, wie Sie diese Methoden effizient implementieren können, besteht darin, Kapitel 3 von Effective Java zu lesen .
quelle
hashCode()
.Einfach ausgedrückt, die equals-Methode in Object prüft auf Referenzgleichheit, wobei zwei Instanzen Ihrer Klasse bei gleichen Eigenschaften immer noch semantisch gleich sein können. Dies ist beispielsweise wichtig, wenn Sie Ihre Objekte in einen Container legen, der Equals und Hashcode verwendet, wie z. B. HashMap und Set . Nehmen wir an, wir haben eine Klasse wie:
Wir erstellen zwei Instanzen mit derselben ID :
Ohne überschreibende Gleichheit erhalten wir:
Richtig? Na vielleicht, wenn du das willst. Angenommen, wir möchten, dass Objekte mit derselben ID dasselbe Objekt sind, unabhängig davon, ob es sich um zwei verschiedene Instanzen handelt. Wir überschreiben die Gleichheit (und den Hashcode):
Für die Implementierung von Equals und Hashcode kann ich die Verwendung der Hilfsmethoden von Guava empfehlen
quelle
Identität ist nicht Gleichheit.
==
Identität des Bedienertests .equals(Object obj)
Methode vergleicht Gleichheitstest (dh wir müssen Gleichheit durch Überschreiben der Methode feststellen)Zuerst müssen wir die Verwendung der Gleichheitsmethode verstehen.
Um Identitätsunterschiede zwischen zwei Objekten zu identifizieren, müssen wir die Methode equals überschreiben.
Zum Beispiel:
Jetzt kann die hashCode-Methode leicht verstehen.
hashCode erzeugt eine Ganzzahl, um Objekte in Datenstrukturen wie HashMap , HashSet zu speichern .
Angenommen, wir haben eine Override-Equals-Methode
Customer
wie oben beschrieben.Während der Arbeit mit der Datenstruktur, wenn wir Objekte in Buckets speichern (Bucket ist ein ausgefallener Name für Ordner). Wenn wir die integrierte Hash-Technik verwenden, werden für mehr als zwei Kunden zwei verschiedene Hashcodes generiert. Wir speichern also dasselbe identische Objekt an zwei verschiedenen Orten. Um diese Art von Problemen zu vermeiden, sollten wir die hashCode-Methode auch basierend auf den folgenden Prinzipien überschreiben.
quelle
Ok, lassen Sie mich das Konzept in sehr einfachen Worten erklären.
Erstens haben wir aus einer breiteren Perspektive Sammlungen, und Hashmap ist eine der Datenstrukturen in den Sammlungen.
Um zu verstehen, warum wir die Methode equals und hashcode überschreiben müssen, müssen wir zuerst verstehen, was Hashmap ist und was funktioniert.
Eine Hashmap ist eine Datenstruktur, in der Schlüsselwert-Datenpaare auf Array-Weise gespeichert werden. Sagen wir a [], wobei jedes Element in 'a' ein Schlüsselwertpaar ist.
Außerdem kann jeder Index in dem obigen Array eine verknüpfte Liste sein, wodurch mehr als ein Wert an einem Index vorliegt.
Warum wird nun eine Hashmap verwendet? Wenn wir in einem großen Array suchen müssen, dann durchsuchen Sie jedes Array, wenn es nicht effizient ist. Welche Hash-Technik sagt uns also, dass wir das Array mit einer gewissen Logik vorverarbeiten und die Elemente basierend auf dieser Logik gruppieren können, dh Hashing
Beispiel: Wir haben das Array 1,2,3,4,5,6,7,8,9,10,11 und wenden eine Hash-Funktion mod 10 an, sodass 1,11 zusammen gruppiert werden. Wenn wir also im vorherigen Array nach 11 suchen müssten, müssten wir das gesamte Array iterieren, aber wenn wir es gruppieren, begrenzen wir unseren Iterationsumfang, wodurch die Geschwindigkeit verbessert wird. Diese Datenstruktur, die zum Speichern aller oben genannten Informationen verwendet wird, kann der Einfachheit halber als 2D-Array betrachtet werden
Abgesehen von der obigen Hashmap wird nun auch angegeben, dass keine Duplikate hinzugefügt werden. Und dies ist der Hauptgrund, warum wir die Gleichheits- und Hashcodes überschreiben müssen
Wenn also gesagt wird, dass dies die interne Funktionsweise von Hashmap erklärt, müssen wir herausfinden, welche Methoden die Hashmap hat und wie sie den oben beschriebenen Regeln folgt
Daher hat die Hashmap eine Methode, die als put (K, V) bezeichnet wird, und gemäß der Hashmap sollte sie den obigen Regeln folgen, um das Array effizient zu verteilen und keine Duplikate hinzuzufügen
Put generiert also zuerst den Hashcode für den angegebenen Schlüssel, um zu entscheiden, in welchen Index der Wert eingegeben werden soll. Wenn an diesem Index nichts vorhanden ist, wird der neue Wert dort hinzugefügt, wenn dort bereits etwas vorhanden ist Dann sollte der neue Wert nach dem Ende der verknüpften Liste an diesem Index hinzugefügt werden. Denken Sie jedoch daran, dass gemäß dem gewünschten Verhalten der Hashmap keine Duplikate hinzugefügt werden sollten. Nehmen wir also an, Sie haben zwei Integer-Objekte aa = 11, bb = 11. Wie bei jedem von der Objektklasse abgeleiteten Objekt besteht die Standardimplementierung für den Vergleich zweier Objekte darin, dass die Referenz und nicht die Werte innerhalb des Objekts verglichen werden. Im obigen Fall bestehen beide, obwohl semantisch gleich, den Gleichheitstest nicht und es besteht die Möglichkeit, dass zwei Objekte mit demselben Hashcode und denselben Werten vorhanden sind, wodurch Duplikate erstellt werden. Wenn wir überschreiben, können wir das Hinzufügen von Duplikaten vermeiden. Sie könnten sich auch darauf beziehenDetailarbeiten
quelle
hashCode()
::Wenn Sie nur die Hash-Code-Methode überschreiben, passiert nichts. Weil es
hashCode
für jedes Objekt als Objektklasse immer neu zurückgibt.equals()
::Wenn Sie nur die gleiche Methode überschreiben,
a.equals(b)
bedeutet dies, dasshashCode
a und b gleich sein müssen, aber nicht passieren dürfen. Weil Sie diehashCode
Methode nicht überschrieben haben .Hinweis: Die
hashCode()
Methode derhashCode
Objektklasse gibt für jedes Objekt immer neu zurück .Wenn Sie also Ihr Objekt in der hashingbasierten Sammlung verwenden müssen, müssen Sie sowohl
equals()
und überschreibenhashCode()
.quelle
Java legt eine Regel fest, die
Wenn wir also in unserer Klasse überschreiben
equals()
, sollten wir diehashcode()
Methode auch überschreiben , um dieser Regel zu folgen. Beide Methodenequals()
undhashcode()
werdenHashtable
beispielsweise verwendet, um Werte als Schlüssel-Wert-Paare zu speichern. Wenn wir das eine und nicht das andere überschreiben, besteht die Möglichkeit, dass dasHashtable
nicht wie gewünscht funktioniert, wenn wir ein solches Objekt als Schlüssel verwenden.quelle
Denn wenn Sie sie nicht überschreiben, verwenden Sie die Standardimplementierung in Object.
Angesichts der Tatsache, dass Instanzgleichheit und Hascode-Werte im Allgemeinen Kenntnisse darüber erfordern, was ein Objekt ausmacht, müssen sie im Allgemeinen in Ihrer Klasse neu definiert werden, um eine konkrete Bedeutung zu haben.
quelle
Um unsere eigenen Klassenobjekte als Schlüssel in Sammlungen wie HashMap, Hashtable usw. zu verwenden, sollten wir beide Methoden (hashCode () und equals ()) überschreiben, indem wir uns mit der internen Funktionsweise der Sammlung vertraut machen. Andernfalls führt dies zu falschen Ergebnissen, die wir nicht erwarten.
quelle
Hinzufügen zu @Lombos Antwort
Wann müssen Sie equals () überschreiben?
Die Standardimplementierung von equals () von Object ist
Dies bedeutet, dass zwei Objekte nur dann als gleich betrachtet werden, wenn sie dieselbe Speicheradresse haben. Dies gilt nur, wenn Sie ein Objekt mit sich selbst vergleichen.
Möglicherweise möchten Sie jedoch zwei Objekte als gleich betrachten, wenn sie für eine oder mehrere ihrer Eigenschaften denselben Wert haben (siehe das Beispiel in der Antwort von @Lombo).
Sie werden also
equals()
in diesen Situationen außer Kraft setzen und Ihre eigenen Bedingungen für die Gleichstellung angeben.Ich habe equals () erfolgreich implementiert und es funktioniert hervorragend. Warum werden sie auch gebeten, hashCode () zu überschreiben?
Solange Sie keine "Hash" -basierten Sammlungen für Ihre benutzerdefinierte Klasse verwenden, ist dies in Ordnung. Aber irgendwann in der Zukunft möchten Sie vielleicht verwenden
HashMap
oderHashSet
und wenn Sie hashCode () nichtoverride
und "korrekt implementieren" , funktionieren diese Hash-basierten Sammlungen nicht wie beabsichtigt.Überschreiben ist nur gleich (Ergänzung zu @Lombos Antwort)
Zunächst prüft HashMap, ob der Hashcode von
second
identisch ist mitfirst
. Nur wenn die Werte gleich sind, wird die Gleichheit im selben Bucket überprüft.Hier unterscheidet sich der Hashcode jedoch für diese beiden Objekte (da sie eine andere Speicheradresse haben als die Standardimplementierung). Daher wird es nicht einmal wichtig sein, die Gleichheit zu überprüfen.
Wenn Ihre überschriebene equals () -Methode einen Haltepunkt enthält, wird dieser nicht aktiviert, wenn sie unterschiedliche Hashcodes haben.
contains()
prüfthashCode()
und nur wenn sie gleich sind, würde es Ihreequals()
Methode aufrufen .Warum können wir die HashMap nicht in allen Buckets auf Gleichheit prüfen lassen? Ich muss also nicht hashCode () überschreiben !!
Dann fehlt Ihnen der Punkt der Hash-basierten Sammlungen. Folgendes berücksichtigen :
Im Folgenden sind die Schlüssel aufgeführt, die in Form von Eimern gespeichert sind.
Angenommen, Sie möchten wissen, ob die Karte den Schlüssel 10 enthält. Möchten Sie alle Eimer durchsuchen? oder Möchten Sie nur einen Eimer durchsuchen?
Basierend auf dem HashCode würden Sie identifizieren, dass wenn 10 vorhanden ist, es in Bucket 1 vorhanden sein muss. Es wird also nur Bucket 1 durchsucht !!
quelle
hashCode()
zur Bestimmung des Buckets und ermittelt mithilfe derequals()
Methode, ob der Wert bereits im Bucket vorhanden ist. Wenn nicht, wird es hinzugefügt, andernfalls wird es durch den aktuellen Wert ersetzthashCode()
, um zuerst den Eintrag (Bucket) undequals()
den Wert in Entry zu findenwenn beide überschrieben werden,
Karte < A >
if equals wird nicht überschrieben
Karte < A >
Wenn hashCode nicht überschrieben wird
Karte < A >
HashCode Equal Contract
quelle
Betrachten Sie die Sammlung von Bällen in einem Eimer in schwarzer Farbe. Ihre Aufgabe ist es, diese Kugeln wie folgt zu färben und für ein geeignetes Spiel zu verwenden.
Für Tennis - Gelb, Rot. Für Cricket - Weiß
Jetzt hat Eimer Kugeln in drei Farben Gelb, Rot und Weiß. Und das hast du jetzt gemacht. Nur du weißt, welche Farbe für welches Spiel ist.
Bälle färben - Hashing. Den Ball für das Spiel auswählen - Gleich.
Wenn Sie die Färbung gemacht haben und jemand den Ball entweder für Cricket oder Tennis wählt, stört ihn die Farbe nicht !!!
quelle
Ich habe mir die Erklärung angesehen: "Wenn Sie nur HashCode überschreiben, wird beim Aufrufen
myMap.put(first,someValue)
zuerst der HashCode berechnet, der HashCode berechnet und in einem bestimmten Bucket gespeichert. Wenn Sie ihn aufrufenmyMap.put(first,someOtherValue)
, sollte er gemäß der Kartendokumentation zuerst durch Second ersetzt werden, da sie gleich sind." (gemäß unserer Definition). " ::Ich denke, wenn wir
myMap
das zweite Mal hinzufügen , sollte es das 'zweite' Objekt seinmyMap.put(second,someOtherValue)
quelle
1) Der häufigste Fehler ist im folgenden Beispiel dargestellt.
Das grüne Auto wurde nicht gefunden
2. Problem verursacht durch hashCode ()
Das Problem wird durch die nicht überschriebene Methode verursacht
hashCode()
. Der Vertrag zwischenequals()
undhashCode()
ist:Wenn zwei Objekte denselben Hashcode haben, können sie gleich sein oder nicht.
quelle
Dies ist nützlich, wenn Sie Wertobjekte verwenden . Das Folgende ist ein Auszug aus dem Portland Pattern Repository :
quelle
Angenommen, Sie haben eine Klasse (A), die zwei andere (B) (C) aggregiert, und Sie müssen Instanzen von (A) in der Hashtabelle speichern. Die Standardimplementierung ermöglicht nur die Unterscheidung von Instanzen, nicht jedoch nach (B) und (C). Zwei Instanzen von A könnten also gleich sein, aber standardmäßig können Sie sie nicht korrekt vergleichen.
quelle
Die Methoden equals und hashcode werden in der Objektklasse definiert. Wenn die Methode equals true zurückgibt, geht das System standardmäßig weiter und überprüft den Wert des Hash-Codes. Wenn der Hash-Code der beiden Objekte ebenfalls nur identisch ist, werden die Objekte als gleich betrachtet. Wenn Sie also nur die Methode equals überschreiben, zeigt der vom System definierte Hashcode möglicherweise nicht an, dass die beiden Objekte gleich sind, obwohl die überschriebene Methode equals 2 Objekte als gleich anzeigt. Wir müssen also auch den Hash-Code überschreiben.
quelle
true
für zurückgebenequals
, nicht als übereinstimmend angesehen werden. Wenn Sammlungen jedoch feststellen, dass Dinge nicht denselben Hash-Code haben können, bemerken sie wahrscheinlich nicht, dass sie gleich sind.Gleichheits- und Hashcode-Methoden in Java
Dies sind Methoden der Klasse java.lang.Object, die die Superklasse aller Klassen ist (auch benutzerdefinierte Klassen und andere in der Java-API definierte).
Implementierung:
public boolean equals (Object obj)
Diese Methode prüft einfach, ob zwei Objektreferenzen x und y auf dasselbe Objekt verweisen. dh es wird geprüft, ob x == y ist.
Es ist reflexiv: Für jeden Referenzwert x sollte x.equals (x) true zurückgeben.
Es ist symmetrisch: Für alle Referenzwerte x und y sollte x.equals (y) genau dann true zurückgeben, wenn y.equals (x) true zurückgibt.
Es ist transitiv: Wenn für alle Referenzwerte x, y und z x.equals (y) true und y.equals (z) true zurückgibt, sollte x.equals (z) true zurückgeben.
Es ist konsistent: Für alle Referenzwerte x und y geben mehrere Aufrufe von x.equals (y) konsistent true oder konsistent false zurück, sofern keine Informationen geändert werden, die für gleiche Vergleiche für das Objekt verwendet werden.
public int hashCode ()
Diese Methode gibt den Hashcode-Wert für das Objekt zurück, für das diese Methode aufgerufen wird. Diese Methode gibt den Hash-Code-Wert als Ganzzahl zurück und wird zugunsten von Hashing-basierten Auflistungsklassen wie Hashtable, HashMap, HashSet usw. unterstützt. Diese Methode muss in jeder Klasse überschrieben werden, die die Methode equals überschreibt.
Der allgemeine Vertrag von hashCode lautet:
Immer wenn es während einer Ausführung einer Java-Anwendung mehr als einmal für dasselbe Objekt aufgerufen wird, muss die hashCode-Methode konsistent dieselbe Ganzzahl zurückgeben, sofern keine Informationen geändert werden, die für gleiche Vergleiche für das Objekt verwendet werden.
Diese Ganzzahl muss von einer Ausführung einer Anwendung zu einer anderen Ausführung derselben Anwendung nicht konsistent bleiben.
Wenn zwei Objekte gemäß der Methode equals (Object) gleich sind, muss der Aufruf der hashCode-Methode für jedes der beiden Objekte dasselbe ganzzahlige Ergebnis liefern.
Es ist nicht erforderlich, dass der Aufruf der hashCode-Methode für jedes der beiden Objekte unterschiedliche ganzzahlige Ergebnisse liefern muss, wenn zwei Objekte gemäß der Methode equals (java.lang.Object) ungleich sind. Der Programmierer sollte sich jedoch bewusst sein, dass das Erzeugen unterschiedlicher ganzzahliger Ergebnisse für ungleiche Objekte die Leistung von Hashtabellen verbessern kann.
Ressourcen:
JavaRanch
Bild
quelle
Wenn Sie im folgenden Beispiel die Überschreibung für Gleichheit oder Hashcode in der Person-Klasse auskommentieren, kann dieser Code Toms Reihenfolge nicht nachschlagen. Die Verwendung der Standardimplementierung von Hashcode kann zu Fehlern bei der Suche nach Hashtabellen führen.
Was ich unten habe, ist ein vereinfachter Code, der die Reihenfolge der Personen nach Person aufruft. Die Person wird als Schlüssel in der Hashtabelle verwendet.
quelle
String-Klassen- und Wrapper-Klassen haben eine andere Implementierung
equals()
undhashCode()
Methoden als die Object-Klasse. Die Methode equals () der Objektklasse vergleicht die Referenzen der Objekte und nicht den Inhalt. Die Methode hashCode () der Object-Klasse gibt für jedes einzelne Objekt einen eigenen Hashcode zurück, unabhängig davon, ob der Inhalt identisch ist.Dies führt zu Problemen, wenn Sie die Map-Sammlung verwenden und der Schlüssel vom Typ Persistent, vom Typ StringBuffer / Builder ist. Da sie im Gegensatz zur String-Klasse equals () und hashCode () nicht überschreiben, gibt equals () false zurück, wenn Sie zwei verschiedene Objekte vergleichen, obwohl beide denselben Inhalt haben. Dadurch wird die HashMap dazu gebracht, dieselben Inhaltsschlüssel zu speichern. Das Speichern derselben Inhaltsschlüssel bedeutet, dass die Map-Regel verletzt wird, da Map überhaupt keine doppelten Schlüssel zulässt. Daher überschreiben Sie die Methoden equals () sowie hashCode () in Ihrer Klasse und stellen die Implementierung bereit (IDE kann diese Methoden generieren), sodass sie genauso funktionieren wie String's equals () und hashCode () und dieselben Inhaltsschlüssel verhindern.
Sie müssen die hashCode () -Methode zusammen mit equals () überschreiben, da equals () gemäß dem Hashcode funktioniert.
Darüber hinaus hilft das Überschreiben der hashCode () -Methode zusammen mit equals (), den Vertrag equals () - hashCode () zu intaktieren: "Wenn zwei Objekte gleich sind, müssen sie denselben Hashcode haben."
Wann müssen Sie eine benutzerdefinierte Implementierung für hashCode () schreiben?
Wie wir wissen, basiert die interne Arbeitsweise von HashMap auf dem Prinzip des Hashing. Es gibt bestimmte Buckets, in denen Eintragssätze gespeichert werden. Sie passen die Implementierung von hashCode () an Ihre Anforderungen an, sodass Objekte derselben Kategorie in demselben Index gespeichert werden können. Wenn Sie die Werte mithilfe der
put(k,v)
Methode in der Map-Sammlung speichern , lautet die interne Implementierung von put ():Das heißt, es wird ein Index generiert und der Index wird basierend auf dem Hashcode eines bestimmten Schlüsselobjekts generiert. Lassen Sie diese Methode also Hashcode gemäß Ihren Anforderungen generieren, da dieselben Hashcode-Eintragssätze in demselben Bucket oder Index gespeichert werden.
Das ist es!
quelle
hashCode()
Methode wird verwendet, um eine eindeutige Ganzzahl für ein bestimmtes Objekt zu erhalten. Diese ganze Zahl ist , für die Bestimmung der Lage Eimer verwendet, wenn dieses Objekt in einigen gespeichert werden mussHashTable
,HashMap
wie Datenstruktur. Standardmäßig gibt diehashCode()
Methode von Object eine ganzzahlige Darstellung der Speicheradresse zurück, in der das Objekt gespeichert ist.Die
hashCode()
Methode von Objekten wird verwendet, wenn wir sie in einHashTable
,HashMap
oder einfügenHashSet
. Mehr dazuHashTables
auf Wikipedia.org als Referenz.Um einen Eintrag in die Kartendatenstruktur einzufügen, benötigen wir sowohl Schlüssel als auch Wert. Wenn sowohl Schlüssel als auch Werte benutzerdefinierte Datentypen sind, bestimmt
hashCode()
der Schlüssel, wo das Objekt intern gespeichert werden soll. Wenn Sie das Objekt auch von der Karte aus nachschlagen müssen, bestimmt der Hash-Code des Schlüssels, wo nach dem Objekt gesucht werden soll.Der Hash-Code zeigt intern nur auf einen bestimmten "Bereich" (oder eine Liste, einen Bucket usw.). Da verschiedene Schlüsselobjekte möglicherweise denselben Hashcode haben können, ist der Hashcode selbst keine Garantie dafür, dass der richtige Schlüssel gefunden wird. Das
HashTable
iteriert dann diesen Bereich (alle Schlüssel mit demselben Hashcode) und verwendet die Schlüsselmethodeequals()
, um den richtigen Schlüssel zu finden. Sobald der richtige Schlüssel gefunden wurde, wird das für diesen Schlüssel gespeicherte Objekt zurückgegeben.Wie wir sehen können, wird beim Speichern und Nachschlagen von Objekten in a eine Kombination der Methoden
hashCode()
undequals()
verwendetHashTable
.ANMERKUNGEN:
Verwenden Sie zum Generieren immer dieselben Attribute eines Objekts
hashCode()
undequals()
beides. Wie in unserem Fall haben wir die Mitarbeiter-ID verwendet.equals()
muss konsistent sein (wenn die Objekte nicht geändert werden, muss immer derselbe Wert zurückgegeben werden).Wann immer
a.equals(b)
, danna.hashCode()
muss das gleiche sein wieb.hashCode()
.Wenn Sie einen überschreiben, sollten Sie den anderen überschreiben.
http://parameshk.blogspot.in/2014/10/examples-of-comparable-comporator.html
quelle
hashCode()
wird nicht verwendet, um für jedes Objekt eine eindeutige Ganzzahl zurückzugeben. Das ist unmöglich. Sie haben dies selbst im zweiten Satz des vierten Absatzes widersprochen.IMHO heißt es in der Regel: Wenn zwei Objekte gleich sind, sollten sie denselben Hash haben, dh gleiche Objekte sollten gleiche Hashwerte erzeugen.
Wie oben angegeben, ist default equals () in Object ==, was einen Vergleich der Adresse durchführt. HashCode () gibt die Adresse in einer Ganzzahl (Hash der tatsächlichen Adresse) zurück, die wiederum für ein bestimmtes Objekt unterschiedlich ist.
Wenn Sie die benutzerdefinierten Objekte in den Hash-basierten Sammlungen verwenden müssen, müssen Sie sowohl equals () als auch hashCode () überschreiben. Beispiel Wenn ich das HashSet der Mitarbeiterobjekte beibehalten möchte, wenn ich keinen stärkeren hashCode und equals verwende Möglicherweise überschreibe ich die beiden verschiedenen Mitarbeiterobjekte. Dies passiert, wenn ich das Alter als hashCode () verwende. Ich sollte jedoch den eindeutigen Wert verwenden, der die Mitarbeiter-ID sein kann.
quelle
Damit Sie nach doppelten Objekten suchen können, benötigen wir einen benutzerdefinierten Gleichheits- und Hashcode.
Da Hashcode immer eine Zahl zurückgibt, ist es immer schnell, ein Objekt mit einer Zahl anstelle eines alphabetischen Schlüssels abzurufen. Wie wird es gehen? Angenommen, wir haben ein neues Objekt erstellt, indem wir einen Wert übergeben haben, der bereits in einem anderen Objekt verfügbar ist. Jetzt gibt das neue Objekt den gleichen Hashwert wie ein anderes Objekt zurück, da der übergebene Wert der gleiche ist. Sobald derselbe Hashwert zurückgegeben wird, wechselt JVM jedes Mal zur gleichen Speicheradresse. Wenn mehr als ein Objekt für denselben Hashwert vorhanden ist, wird die Methode equals () verwendet, um das richtige Objekt zu identifizieren.
quelle
Wenn Sie Ihr benutzerdefiniertes Objekt als Schlüssel in Map speichern und abrufen möchten, sollten Sie immer equals und hashCode in Ihrem benutzerdefinierten Objekt überschreiben. Z.B:
Hier wird p1 & p2 als nur ein Objekt betrachtet und die
map
Größe wird nur 1 sein, weil sie gleich sind.quelle
Testklasse
In Object Class wird equals (Object obj) verwendet, um den Adressvergleich zu vergleichen. Wenn Sie in der Testklasse zwei Objekte vergleichen, entspricht dies der Methode false, aber wenn wir Hashcode () überschreiben, kann der Inhalt verglichen und das richtige Ergebnis erzielt werden.
quelle
Wenn Sie überschreiben
equals()
und nichthashcode()
, werden Sie kein Problem finden, es sei denn, Sie oder jemand anderes verwendet diesen Klassentyp in einer Hash-Sammlung wieHashSet
. Die Leute vor mir haben die dokumentierte Theorie mehrmals klar erklärt. Ich bin nur hier, um ein sehr einfaches Beispiel zu liefern.Stellen Sie sich eine Klasse vor, deren
equals()
Bedürfnis etwas Angepasstes bedeuten muss:Betrachten Sie nun diese Hauptklasse: -
Dies ergibt die folgende Ausgabe: -
Ich bin mit den Ergebnissen zufrieden. Aber wenn ich nicht überschrieben habe
hashCode()
, wird es einen Albtraum verursachen, da ObjekteRishav
mit demselben Mitgliedsinhalt nicht mehr als eindeutig behandelthashCode
werden, da sie unterschiedlich sind, wie durch das Standardverhalten erzeugt. Hier wäre die Ausgabe: -quelle
Beide Methoden sind in der Objektklasse definiert. Und beide sind in ihrer einfachsten Implementierung. Wenn Sie diesen Methoden also eine weitere Implementierung hinzufügen möchten, müssen Sie sie in Ihrer Klasse überschreiben.
Zum Beispiel überprüft die Methode equals () im Objekt nur ihre Gleichheit in der Referenz. Wenn Sie also auch den Status vergleichen müssen, können Sie diesen überschreiben, wie dies in der String-Klasse der Fall ist.
quelle
Bah - "Sie müssen hashCode () in jeder Klasse überschreiben, die equals () überschreibt."
[aus Effective Java von Joshua Bloch?]
Ist das nicht falsch herum? Das Überschreiben von hashCode impliziert wahrscheinlich, dass Sie eine Hash-Key-Klasse schreiben, das Überschreiben von equals jedoch sicherlich nicht. Es gibt viele Klassen, die nicht als Hash-Schlüssel verwendet werden, aber aus einem anderen Grund eine Methode zum Testen der logischen Gleichheit wünschen. Wenn Sie dafür "gleich" wählen, können Sie durch übereifrige Anwendung dieser Regel aufgefordert werden, eine HashCode-Implementierung zu schreiben. Alles, was erreicht wird, ist das Hinzufügen von ungetestetem Code in die Codebasis, ein Übel, das darauf wartet, in Zukunft jemanden zu stolpern. Auch das Schreiben von Code, den Sie nicht benötigen, ist nicht agil. Es ist einfach falsch (und eine von einer Idee generierte wird wahrscheinlich nicht mit Ihren handgefertigten Gleichen kompatibel sein).
Sicherlich hätten sie eine Schnittstelle für Objekte vorschreiben sollen, die als Schlüssel verwendet werden sollen? Unabhängig davon sollte Object niemals standardmäßig hashCode () und equals () imho angegeben haben. Es wird wahrscheinlich viele kaputte Hash-Sammlungen ermutigt.
Trotzdem denke ich, dass die "Regel" von hinten nach vorne geschrieben ist. In der Zwischenzeit werde ich weiterhin vermeiden, "Gleichheit" für Gleichheitstestmethoden zu verwenden :-(
quelle