2010-10-06 25 views
8

A volte ho bisogno di implementare il metodo hashCode() di un oggetto combinando gli hashCode dei suoi vari membri di istanza. Ad esempio, se l'obj combinatoria ha membri a, b, ec, vedo spesso ppl implementarlo comequal è il modo migliore per implementare hashCode()?


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

Da dove viene questo numero magico 31 viene? È la lunghezza di 4 byte o solo un numero primo?

C'è qualche altro modo preferito/standard per implementare hashCode()?

+0

Simile (ma non necessariamente duplicato): http://stackoverflow.com/questions/3613102/why-use-a-prime-number-in-hashcode –

+0

Il numero 31 è utilizzato in String.hashCode() Ciò rende un buon primo dato che non ci sono molti diversi caratteri possibili, tuttavia io tendo ad usare numeri primi più grandi. Un buon sito per i primi "interessanti" è http://primes.utm.edu/curios/ –

risposta

8

Vedere Effective Java's recipe. È solo la migliore fonte, a mani basse.

L'uso di un numero primo è solo per cercare di ottenere una distribuzione ragionevolmente buona senza conoscere il dominio. Ci vorrà un po 'per traboccare allo stesso valore. Il valore 31 è piuttosto arbitrario se ricordo correttamente.

Secondo Bloch (usa 17 come valore iniziale e 37 come moltiplicatore costante):

Un valore iniziale diverso da zero viene utilizzato (...) quindi il valore hash è applicabile iniziale campi il cui valore hash (...) è zero. Se è stato utilizzato lo zero come , il valore iniziale (...) del valore hash complessivo non viene modificato da tali campi iniziali , che potrebbero aumentare le collisioni. Il valore 17 è arbitrario.
...
Il moltiplicatore 37 è stato scelto perché è un numero primo dispari. Se fosse pari e la moltiplicazione traboccò, le informazioni sarebbero andate perse perché la moltiplicazione di due equivaleva allo spostamento. I vantaggi dell'utilizzo di un numero primo sono inferiori a , ma è normale utilizzare i numeri primi a questo scopo.

+0

CW dato che sto citando sfacciatamente Bloch. –

+4

Nella seconda edizione di Effective Java, Josh Bloch usa 31 anziché 37. Spiega questa scelta: "Una bella proprietà di 31 è che la moltiplicazione può essere sostituita da uno spostamento e una sottrazione per prestazioni migliori:' 31 * i = = (i << 5) - i'. Le moderne macchine virtuali eseguono automaticamente questo tipo di ottimizzazione. " – ColinD

2

Usa HashCodeBuilder da Commons Lang:

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

Vedi l'API di modi per farlo senza l'utilizzo di riflessione. Puoi dire quali campi includere o quali ignorare.

Vedere anche EqualsBuilder, per ignorare il metodo di uguale.

6

Una buona opzione è il metodo GuavaObjects.hashCode. Ci vuole un numero qualsiasi di argomenti e crea un codice hash basato su di essi:

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

fondamentalmente, il codice hash dovrebbe consistere del parametro chiave della vostra POJO. Un esempio è sotto.

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

Nell'esempio precedente, l'id e il nome del roll sono il parametro chiave di quel POJO.

È una buona pratica se si aggiungono solo quei parametri nel metodo hashCode che si aggiunge nel metodo Eqauls dello stesso POJO.

1

Generalo usando il tuo IDE.

0

Credo che quanto segue sia una buona pratica per scenari semplici: Se la classe contiene membri di sola lettura, sarebbero buoni candidati per generare l'hashcode dell'oggetto. Se la classe, tuttavia, contiene solo i membri mutanti, è possibile creare un campo int readonly che ottenga il valore in base ai valori non nulli passati al costruttore.

Problemi correlati