2010-10-06 25 views
8

Parfois, j'ai besoin d'implémenter une méthode hashCode() d'obj en combinant les hashCodes de ses plusieurs membres d'instance. Par exemple, si le combinatoires obj a des membres a, b, et c, je vois souvent ppl comme la mise en œuvreQuelle est la meilleure façon d'implémenter hashCode()?


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

Où ce chiffre magique 31 vient? Est-ce la longueur de 4 octets ou juste un nombre premier?

Existe-t-il un autre moyen préféré/standard d'implémenter hashCode()?

+0

Similaire (mais pas nécessairement en double): http://stackoverflow.com/questions/3613102/why-use-a-prime-number-in-hashcode –

+0

Le prime 31 est utilisé dans String.hashCode() Cela rend un bon premier car il n'y a pas beaucoup de différents caractères possibles, mais j'ai tendance à utiliser des nombres premiers plus grands. Un bon site pour les nombres premiers "intéressants" est http://primes.utm.edu/curios/ –

Répondre

8

Voir Effective Java's recipe. C'est juste la meilleure source, haut la main.

L'utilisation d'un nombre premier est juste pour essayer d'obtenir une distribution raisonnablement bonne sans connaître le domaine. Il faudra un certain temps pour déborder à la même valeur. La valeur 31 est assez arbitraire si je me souviens bien.

Selon Bloch (il utilise 17 comme valeur initiale et 37 comme le multiplicateur constant):

une valeur initiale non nulle est utilisée (...) de sorte que la valeur de hachage sera affectée par initial champs dont la valeur de hachage (...) est nulle. Si zéro était utilisé comme la valeur initiale (...) la valeur de hachage globale ne serait pas affectée par de tels champs initiaux , ce qui pourrait augmenter les collisions. La valeur 17 est arbitraire.
...
Le multiplicateur 37 a été choisi car il s'agit d'un nombre premier impair. S'il était pair et la multiplication débordait, l'information serait perdue parce que la multiplication par deux équivaut à un décalage de . Les avantages d'utiliser un nombre premier sont moins , mais il est classique d'utiliser des nombres premiers à cette fin.

+0

CW puisque je ne fais que citer sans vergogne Bloch. –

+4

Dans la deuxième édition de Effective Java, Josh Bloch utilise 31 plutôt que 37. Il explique ce choix: "Une belle propriété de 31 est que la multiplication peut être remplacée par un décalage et une soustraction pour de meilleures performances:' 31 * i = = (i << 5) - Les machines virtuelles modernes font automatiquement ce type d'optimisation. " – ColinD

2

utilisation HashCodeBuilder de Lang Commons:

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

Voir l'API des façons de le faire sans utiliser la réflexion. Vous pouvez lui dire quels champs inclure ou ignorer.

Voir aussi EqualsBuilder pour remplacer une méthode égale.

6

Une bonne option est Guava méthode Objects.hashCode. Il prend un certain nombre d'arguments et crée un hashcode basé sur eux

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

essentiellement, votre code de hachage doit comprendre le paramètre clé de votre POJO. Un exemple est ci-dessous.

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; 
} 

Dans l'exemple ci-dessus, l'identificateur de rouleau et le nom sont le paramètre clé de ce POJO.

C'est une bonne pratique si vous ajoutez seulement ces paramètres dans la méthode hashCode que vous ajoutez dans la méthode Eqauls du même POJO.

1

Générez-le en utilisant votre IDE.

0

Je crois que ce qui suit est une bonne pratique pour les scénarios simples: Si votre classe contient des membres en lecture seule, ils seraient de bons candidats pour générer le hashcode de l'objet. Si votre classe, cependant, ne contient que les membres mutants, vous pouvez créer un champ int readonly qui obtient la valeur basée sur les valeurs non nulles passées au constructeur.