Beste Umsetzung für die hashCode-Methode für eine Sammlung
Tun, wie wir entscheiden uns für die beste Umsetzung hashCode()
Methode für eine Sammlung (unter der Annahme, dass die equals-Methode überschrieben wurde richtig) ?
- mit Java 7+, ich denke
Objects.hashCode(collection)
sollte eine perfekte Lösung! - Ich glaube nicht, dass das beantwortet die Frage überhaupt -, die Methode gibt einfach
collection.hashCode()
(hg.openjdk.java.net/jdk7/jdk7/jdk/file/9b8c96f96a0f/src/share/...)
Du musst angemeldet sein, um einen Kommentar abzugeben.
Die beste Umsetzung? Das ist eine schwierige Frage, denn es hängt von der Nutzung Muster.
Einer für fast alle Fälle gute Umsetzung vorgeschlagen wurde Josh Bloch's Effektive Java - in Artikel 8 (zweite Ausgabe). Das beste ist, suchen Sie es dort, weil der Autor erklärt es, warum der Ansatz ist gut.
Eine kurze version
Erstellen Sie eine
int result
und vergeben Sie einen nicht-null - Wert.Für jedes Feld
f
getestet, in derequals()
- Methode, Berechnung eines hash-codec
durch:boolean
:berechnen
(f ? 0 : 1)
;byte
,char
,short
oderint
: berechnen(int)f
;long
: berechnen(int)(f ^ (f >>> 32))
;float
: berechnenFloat.floatToIntBits(f)
;double
: berechnenDouble.doubleToLongBits(f)
und Griff der return-Wert, wie jeder long-Wert;hashCode()
Methode oder 0, wennf == null
;Kombinieren der hash-Wert
c
mitresult
:Zurück
result
Sollte dies die korrekte Verteilung von hash-Werten für die meisten Situationen verwenden.
result = result << 16 + c
)?true
Zuordnung zu0
undfalse
zu1
, und nicht die andere Weise herum?f
ist ein array, haben Sie auch die Möglichkeit, diejava.util.Arrays.hashCode
Methoden zu berechnen, dass der Bereich der hash-Wert.double
wie .Net, und meine letzten Tests haben gezeigt, dass es sehr schlecht ist, wenn deine doubles sind nicht wirklich zufällig, aber wirklich zahlen, oder haben nur ein oder zwei Dezimalstellen. Die re-hash-Funktion ausHashMap
hilft, aber noch nicht so gut, wie nur mit dem HashCode fürint
auf den Wert in diesem Fall.Wenn Sie glücklich sind, mit der Effektiven Implementierung in Java empfohlen von dmeister, die Sie verwenden können, eine Bibliothek nennen, anstatt Ihre eigenen Rollen:
Dies erfordert entweder Guave (
com.google.common.base.Objects.hashCode
) oder der standard-Bibliothek in Java 7 (java.util.Objects.hash
), aber Sie funktioniert auf die gleiche Weise.hashCode
ist, wenn Sie eine benutzerdefinierteequals
, und das ist genau das, was diese Bibliothek Methoden ausgelegt sind. Die Dokumentation ist ganz klar auf Ihr Verhalten in Bezug aufequals
. Eine Bibliothek, die Umsetzung hat nicht den Anspruch, entbindet Sie von dem wissen, was die Merkmale einer richtigenhashCode
Umsetzung sind - diese Bibliotheken machen es einfacher für Sie zu implementieren, so ist eine konforme Implementierung für die Mehrheit der Fälle, in denenequals
wird überschrieben.java.util.Objects.hash(...)
Methode als die Guavecom.google.common.base.Objects.hashCode(...)
Methode. Ich denke die meisten Menschen würden wählen Sie die standard-Bibliothek über eine zusätzliche Abhängigkeit.hashCode()
für ein array ist nur seinejava.lang.System.identityHashCode(...)
.Ist es besser, um die Funktionalität von Eclipse, die hat einen ziemlich guten job, und Sie können Ihre Bemühungen und Energie in die Entwicklung der business-Logik.
Obwohl dies im Zusammenhang mit
Android
Dokumentation (Wayback Machine) und Meinen eigenen code auf Github, es funktioniert für Java im Allgemeinen. Meine Antwort ist eine Erweiterung der dmeister Antwort nur mit code, der ist viel einfacher zu Lesen und zu verstehen.BEARBEITEN
In der Regel, wenn Sie überschreiben
hashcode(...)
Sie auch außer Kraft setzen möchtenequals(...)
. Also für diejenigen, die bereits umgesetztequals
, hier ist eine gute Referenz von meinem Github...Stellen Sie zunächst sicher, dass equals korrekt implementiert. Von einen IBM DeveloperWorks Artikel:
Dann stellen Sie sicher, dass Ihre Beziehung mit hashCode Hinsicht auf den Kontakt (aus dem gleichen Artikel):
Endlich eine gute hash-Funktion sollte sich bemühen, den Ansatz der ideale hash-Funktion.
about8.blogspot.com Sie sagte
Kann ich nicht Zustimmen mit Ihnen. Wenn zwei Objekte den gleichen hashcode es muss nicht bedeuten, dass Sie gleich sind.
Wenn A gleich B, dann A. hashcode gleich sein müssen, um B. hascode
aber
wenn A. hashcode equals B. hascode es bedeutet nicht, muß A gleich B ist
(A != B) and (A.hashcode() == B.hashcode())
, das ist, was wir nennen hash-Funktion Kollision. Es ist, weil die hash-Funktion die codomain ist immer begrenzt, während es die domain in der Regel nicht. Je größer die codomain ist, desto weniger oft wird die Kollision stattfinden soll. Gute hash-Funktion zurückgeben soll, unterschiedliche hashes für die verschiedenen Objekte mit der größten Möglichkeit, erreichbar zu besonderen codomain Größe. Es kann selten garantiert werden obwohl.Wenn Sie eclipse verwenden, können Sie generieren
equals()
undhashCode()
mit:Mithilfe dieser Funktion können Sie entscheiden die Felder Sie verwenden möchten, für die Gleichheit und hash-code-Berechnung und Eclipse generiert die entsprechenden Methoden.
Es ist eine gute Umsetzung des Effektive Java - 's
hashcode()
undequals()
Logik in Apache Commons Lang. Kasse HashCodeBuilder und EqualsBuilder.Objects
- Klasse bietethash(Object ..args)
&equals()
Methoden von Java7 auf. Diese werden empfohlen für alle Anwendungen, die mit dem jdk 1.7+IdentityHashMap
). FWIW, ich verwenden Sie eine id-basierte hashCode und equals für alle Entitäten.Nur eine kurze Notiz, die für das abschließen der andere ausführlichere Antwort (in der Bezeichnung des Codes):
Wenn ich die Frage prüfen, wie-kann-ich-erstelle-ein-hash-Tabelle in java und vor allem die jGuru FAQ-Eintrag, ich glaube, einige andere Kriterien, auf die sich ein hash-code kann beurteilt werden, sind:
Wenn ich verstehe deine Frage richtig, haben Sie eine benutzerdefinierte Auflistungsklasse (also eine neue Klasse, die sich aus der Collection-Schnittstelle) und die Sie implementieren möchten, die hashCode () - Methode.
Wenn Sie Ihre Sammlung Klasse extends AbstractList, dann brauchen Sie sich keine sorgen machen, es gibt bereits eine Implementierung von equals() und hashCode (), das funktioniert durch die Iteration über alle Objekte und das hinzufügen von Ihrer hashCodes() zusammen.
Nun, wenn das, was Sie wollen, ist der beste Weg zur Berechnung des hashcodes für eine bestimmte Klasse, die ich normalerweise verwenden ^ (bitweise exklusiv oder) operator für die Verarbeitung aller Felder, die ich verwenden in der equals-Methode:
@about8 : es ist eine ziemlich ernste Fehler gibt.
gleichen hashcode
möchten Sie wahrscheinlich so etwas wie
(kann man hashCode direkt von int in Java in diesen Tagen? Ich denke, es muss einige autocasting.. wenn das der Fall ist, überspringen Sie die toString, es ist hässlich.)
foo
undbar
führt zu den gleichenhashCode
. IhretoString
AFAIK nicht kompilieren, und wenn es funktioniert, dann es ist schrecklich ineffizient. So etwas wie109 * getFoo().hashCode() + 57 * getBar().hashCode()
ist schneller, einfacher und erzeugt keinen unnötigen Kollisionen.Als Sie ausdrücklich gebeten, die für Sammlungen, ich möchte noch hinzufügen, ein Aspekt, den die anderen Antworten noch nicht erwähnt habe, aber: Eine HashMap nicht erwarten, dass Sie Ihre Schlüssel zu ändern hashcode, sobald Sie der Sammlung Hinzugefügt. Würde den ganzen Zweck vereiteln...
Verwenden Sie die Reflexion der Methoden auf der Basis von Apache Commons EqualsBuilder und HashCodeBuilder.
Benutze ich einen kleinen wrapper um
- Arrays.deepHashCode(...)
, weil es Griffe arrays als Parameter bereitgestellt korrektalle hashing-Methode, die gleichmäßig verteilt den hash-Wert über das mögliche Spektrum ist eine gute Umsetzung. Wirksame java ( http://books.google.com.au/books?id=ZZOiqZQIbRMC&dq=effective+java&pg=PP1&ots=UZMZ2siN25&sig=kR0n73DHJOn-D77qGj0wOxAxiZw&hl=en&sa=X&oi=book_result&resnum=1&ct=result ) , es ist ein guter Tipp, gibt es für die hashcode-Implementierung (Punkt 9 glaube ich...).
Ich lieber mit utility-Methoden fromm Google-Kollektionen lib aus die Objekte der Klasse das hilft mir, um meinen code sauber. Sehr oft
equals
undhashcode
Methoden sind aus IDE-Vorlage, damit Ihr nicht sauber zu Lesen.Hier ist ein weiteres JDK 1.7+ Ansatz demonstration mit Oberklasse-Logik berücksichtigt werden. Ich sehe es als ziemlich praktisch mit Klasse Object hashCode() berücksichtigt, Reine JDK-Abhängigkeit und ohne zusätzliche manuelle arbeiten. Bitte beachten Sie
Objects.hash()
ist null-tolerant.Habe ich keine
equals()
Umsetzung aber in Wirklichkeit werden Sie natürlich brauchen.Die standard-Umsetzung ist schwach, und es führt zu unnötigen Kollisionen. Stellen Sie sich eine
Nun,
und
haben die gleichen
hashCode
nämlich31*(a+b) + c
als Multiplikator verwendet fürList.hashCode
wird wiederverwendet hier. Natürlich, Kollisionen sind unvermeidlich, aber produziert unnötig Kollisionen ist einfach nur... unnötig.Gibt es nichts wesentlich smart über die Verwendung
31
. Der Multiplikator muss ungerade sein, um zu vermeiden, dass Informationen (auch Multiplikator verliert zumindest das wichtigste bit, die ein Vielfaches von vier zu verlieren, zwei, usw.). Jede ungerade Multiplikator nutzbar ist. Kleine Multiplikatoren kann führen zu einer schnelleren Berechnung (JIT verwenden können Verschiebungen und Ergänzungen), aber angesichts der Tatsache, dass die Multiplikation hat Latenz von nur drei Zyklen auf moderne Intel/AMD, das spielt eigentlich kaum eine Rolle. Kleine Multiplikatoren führt auch zu mehr Kollisionen für kleine Eingänge, die möglicherweise auch mal ein problem.Mithilfe eines prime ist sinnlos, wie Primzahlen haben keine Bedeutung in dem ring Z/(2**32).
So, ich würde empfehlen, mit einem zufällig gewählten große ungerade Zahl (fühlen Sie sich frei, um eine prime). Als i86/amd64 CPUs können verwenden Sie eine kürzere Anleitung für die Operanden, die den Einbau in ein einzelnes vorzeichenbehaftetes byte, es gibt einen kleinen speed-Vorteil für Multiplikatoren wie 109. Zur Minimierung von Kollisionen, nehmen Sie etwas wie 0x58a54cf5.
Mit verschiedenen Multiplikatoren in den verschiedenen Orten ist hilfreich, aber wahrscheinlich nicht genug, zu rechtfertigen, die zusätzliche Arbeit.
Bei der Kombination von hash-Werten, die ich in der Regel verwenden Sie die Kombination-Methode, die sich auch in der boost c++ Bibliothek, nämlich:
Das macht einen ziemlich guten job, die Gewährleistung für eine gleichmäßige Verteilung. Für einige Diskussion, wie diese Formel funktioniert, siehe StackOverflow-post: Magic number in boost::hash_combine
Es gibt eine gute Diskussion der verschiedenen hash-Funktionen an: http://burtleburtle.net/bob/hash/doobs.html
Für eine einfache Klasse ist es oft am einfachsten zu implementieren, hashCode() basiert auf der Klasse Felder, die geprüft werden, indem die equals () - Implementierung.
Das wichtigste ist, zu halten, hashCode() und equals () - konsequent: wenn equals() gibt true zurück, für zwei Objekte, dann hashCode() sollte den gleichen Wert zurückgeben. Wenn equals() gibt false zurück, dann hashCode() sollte unterschiedliche Werte zurückgeben.
("abc"+""=="ab"+"c"=="a"+"bc"==""+"abc")
. Es ist schwerer Fehler. Es wäre besser bewerten zu können hashcode für beide Felder eingeben und dann berechnen lineare Kombination von Ihnen (vorzugsweise mit Primzahlen als Koeffizienten).foo
undbar
produziert eine unnötige Kollision, zu.