2010-12-14 13 views
7

Per una classe i cui campi sono esclusivamente primitiva, es .:Overriding hashCode() - è abbastanza buono?

class Foo 
{ 
    int a; 
    String b; 
    boolean c; 
    long d; 

    boolean equals(Object o) 
    { 
     if (this == o) return true; 
     if (!(o instanceof Foo)) return false; 
     Foo other = (Foo) o; 
     return a == other.a && b.equals(other.b) && c == other.c && d = other.d; 
    } 
} 

È questo un ragionevolmente "abbastanza buono" modo per scrivere hashCode()?

boolean hashCode() 
{ 
    return (b + a + c + d).hashCode(); 
} 

Cioè, io costruisco un String fuori gli stessi campi che equals() usi, e poi basta usare String#hashCode().

Modifica: Ho aggiornato la mia domanda per includere un campo long. Come deve essere gestito un long in hashCode()? Basta lasciarlo traboccare int?

+0

Anche se non è molto efficiente, dovrebbe funzionare correttamente perché ogni due istanza con tutti gli stessi valori interni avrà lo stesso codice hash. – Gabe

+0

Funzionerà correttamente Non conosco il problema di prestazioni ma sicuramente funzionerà. Se vuoi andare oltre, leggi: http://www.ibm.com/developerworks/java/library/j-jtp05273.html – Necronet

+0

Basta usare [commons-lang's HashCodeBuilder] (http://commons.apache.org/ lang/api-2.5/org/apache/commons/lang/builder/HashCodeBuilder.html) e non preoccuparti mai di questo tipo di cose –

risposta

7

Il tuo codice hash soddisfa la proprietà che se due oggetti sono uguali, i loro codici hash devono essere uguali. Quindi, in questo modo è "abbastanza buono". Tuttavia, è abbastanza semplice creare collisioni nei codici hash che degraderanno le prestazioni delle strutture di dati basate su hash.

avrei implementare in modo leggermente diverso però:

public int hashCode() { 
    return a * 13 + b.hashCode() * 23 + (c? 31: 7); 
} 

si dovrebbe verificare la documentation for the hashCode() method di Object. Descrive le cose che il codice hash deve soddisfare.

+0

Capisco il contratto per 'equals()' e 'hashCode()'. Quello che sto cercando è un modo minimo di sforzo, idiota-resistente, senza sorprese per soddisfare il contratto. Il tuo codice sembra abbastanza ragionevole. Potresti spiegare il motivo della moltiplicazione per i numeri primi? Inoltre, ho aggiornato la mia domanda: come gestisco i campi 'lunghi'? –

+3

@Matt: il percorso "minimo sforzo" e "idiot resistant" utilizza l'IDE per generare il metodo, ad esempio Netbeans genera per una delle mie classi: 'int hash = 5; hash = 37 * hash + (int) (this. id^(this.id >>> 32)); restituisce hash; ' –

+1

@Cononatus: hmm, buon punto.Ho dimenticato" Alt + Shift + S' (Eclipse) –

0

Dipende totalmente da come saranno i vostri dati. Nella maggior parte dei casi, questo sarebbe un buon approccio. Se avrai spesso b con un numero, otterrai alcuni codici duplicati per oggetti non uguali, come mostra la risposta di JacobM. Se sai in anticipo che b non avrà praticamente mai un valore numerico alla fine, allora questo è un ragionevole algoritmo di hashing.