2010-10-06 17 views
8

Manchmal muss ich die hashCode() -Methode eines Objekts implementieren, indem ich die hashCodes seiner verschiedenen Instanzmitglieder kombiniere. wenn die kombinatorische obj Mitglieder a, b und c hat, habe ich oft siehe zum Beispiel ppl implementieren alsWas ist die bevorzugte Methode zur Implementierung von hashCode()?


int hashCode(){ 
    return 31 * 31 * a.hashCode() + 31 * b.hashCode() + c.hashCode(); 
} 

Woher kommt diese magische Zahl 31 kommen aus? Ist es die Länge von 4 Bytes oder nur eine Primzahl?

Gibt es eine andere bevorzugte/standard Art der Implementierung von HashCode()?

+0

Ähnlich (aber nicht unbedingt doppelt): http://stackoverflow.com/questions/3613102/why-use-a-prime-number-in-hashcode –

+0

Die Primzahl 31 wird in String.hashCode() verwendet Dies macht eine gute Primzahl, da es nicht viele verschiedene mögliche Zeichen gibt, jedoch neige ich dazu, größere Primzahlen zu verwenden. Eine gute Seite für "interessante" Primzahlen ist http://primes.utm.edu/curios/ –

Antwort

8

Siehe Effective Java's recipe. Es ist einfach die beste Quelle, die Hände runter.

Die Verwendung einer Primzahl ist nur zu versuchen, eine einigermaßen gute Verteilung zu erhalten, ohne die Domäne zu kennen. Es wird eine Weile dauern, bis der gleiche Wert erreicht ist. Der Wert 31 ist ziemlich willkürlich, wenn ich mich richtig erinnere.

Nach Bloch (17 verwendet er als einen Anfangswert und 37 als Konstantmultiplikator):

Ein von Null abweichenden Anfangswert verwendet wird (...), so dass der Hash-Wert wird durch anfängliche betroffen Felder, deren Hash-Wert (...) Null ist. Wenn Null als der Anfangswert (...) verwendet wurde, würde der gesamte Hash-Wert von solchen Anfangsfeldern nicht beeinflusst werden, was die Kollisionen erhöhen könnte. Der Wert 17 ist beliebig.
...
Der Multiplikator 37 wurde gewählt, weil es eine ungerade Primzahl ist. Wenn es gerade war und die Multiplikation übergelaufen ist, würde die Information verloren gehen, weil die Multiplikation mit zwei dem Verschieben äquivalent ist. Die Vorteile der Verwendung einer Primzahl sind weniger klar, aber es ist üblich, Primzahlen für diesen Zweck zu verwenden.

+0

CW, da ich Bloch nur schamlos zitiere. –

+4

In der zweiten Ausgabe von Effektivem Java verwendet Josh Bloch 31 statt 37. Er erklärt diese Wahl: "Eine nette Eigenschaft von 31 ist, dass die Multiplikation durch eine Verschiebung und eine Subtraktion für bessere Leistung ersetzt werden kann: 31 * i = = (i << 5) - i. Moderne VMs führen diese Art der Optimierung automatisch aus. – ColinD

2

Verwenden HashCodeBuilder von Commons Lang:

public int hashCode() { 
    return HashCodeBuilder.reflectionHashCode(this); 
} 

Siehe die API für Möglichkeiten, es zu tun, ohne Reflexion verwendet wird. Sie können angeben, welche Felder einbezogen werden sollen oder welche ignoriert werden sollen.

Siehe auch EqualsBuilder zum Überschreiben einer equals-Methode.

6

Eine gute Option ist Guava 's Objects.hashCode Methode. Es nimmt eine beliebige Anzahl von Argumenten und erstellt einen Hash-Code auf ihnen basiert:

@Override public int hashCode() { 
    return Objects.hashCode(a, b, c); 
} 
0

im Grunde Ihre Hash-Code sollte der Schlüsselparameter des POJO bestehen. Ein Beispiel ist unten.

public int hashCode() { 
    int hash = 0; 
    if (getRollId() != null) { 
     hash += getRollId().hashCode(); 
    } 
    if (getName() != null) { 
     hash += getName().hashCode(); 
    } 
    return hash == 0 ? System.identityHashCode(this) : hash; 
} 

In dem obigen Beispiel wird die Rolle ID und die Namen sind die Schlüsselparameter dieser POJO.

Es ist eine gute Übung, wenn Sie nur die Parameter in die Methode hashCode einfügen, die Sie in der Methode Eqauls desselben POJO hinzufügen.

1

Generieren Sie es mit Ihrer IDE.

0

Ich glaube, das folgende ist eine gute Praxis für einfache Szenarien: Wenn Ihre Klasse readonly Mitglieder enthält, wären sie gute Kandidaten für die Generierung des Objekts Hashcode. Wenn Ihre Klasse jedoch nur die mutierenden Elemente enthält, könnten Sie ein schreibgeschütztes int-Feld erstellen, das den Wert basierend auf den Nicht-Null-Werten erhält, die an den Konstruktor übergeben werden.

Verwandte Themen