2010-12-14 22 views
7

Dla klasy, których pola są wyłącznie prymitywne, np .:Przesłanianie hashCode() - czy to wystarczy?

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

Czy to rozsądnie „wystarczająco dobry” sposób napisać hashCode()?

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

Oznacza to, że skonstruowanie String z tych samych pól, które equals() zastosowań, a potem po prostu korzystać String#hashCode().

Edytuj: Zaktualizowałem moje pytanie, dodając pole long. W jaki sposób należy obsługiwać long w hashCode()? Po prostu przepuść int?

+0

Chociaż nie jest strasznie wydajna, powinna działać poprawnie, ponieważ dowolne dwa wystąpienia o tych samych wartościach wewnętrznych będą miały ten sam kod skrótu. – Gabe

+0

Będzie działać poprawnie Nie wiem o problemie wydajności, ale na pewno zadziała. Jeśli chcesz pójść dalej, przeczytaj: http://www.ibm.com/developerworks/java/library/j-jtp05273.html – Necronet

+0

Po prostu użyj [HashCodeBuilder] [commons-lang's HashCodeBuilder] (http://commons.apache.org/ lang/api-2.5/org/apache/commons/lang/builder/HashCodeBuilder.html) i nigdy nie musisz się martwić tego typu sprawami: –

Odpowiedz

7

Twój kod skrótu spełnia właściwość, że jeśli dwa obiekty są równe, to ich kody skrótu muszą być równe. W ten sposób jest "wystarczająco dobre". Jednak jest dość proste tworzenie kolizji w kodach haszujących, które obniżą wydajność struktur danych opartych na haszymsie.

bym go wdrożyć, choć nieco inaczej:

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

Należy zapoznać się z documentation for the hashCode() method z Object. Określa to, co musi spełnić kod skrótu.

+0

Rozumiem umowy dla 'równa()' i 'hashCode()'. To, czego szukam, to minimalnie trudny, odporny na idioty, nie zaskakujący sposób na wypełnienie kontraktu. Twój kod wydaje się wystarczająco rozsądny. Czy mógłbyś wyjaśnić przyczynę mnożenia przez liczby pierwsze? Ponadto zaktualizowałem swoje pytanie: jak sobie radzić z polami "długimi"? –

+3

@Matt - Ścieżka "minimalnego wysiłku", idiota odporna "jest używana przez twoje IDE do generowania metody, np. Netbeans generuje dla jednej z moich klas:' int hash = 5; hash = 37 * hash + (int) (this. id^(this.id >>> 32)); return hash; ' –

+1

@Coronatus: hmm, dobry punkt. Zapomniałem o' Alt + Shift + S' (Eclipse) –

0

To całkowicie zależy od tego, jak będą wyglądać Twoje dane. W większości przypadków byłoby to dobre podejście. Jeśli często będziesz mieć numer b, otrzymasz kilka zduplikowanych kodów dla nierównych obiektów, jak pokazuje odpowiedź Jacobma. Jeśli wiesz z wyprzedzeniem, że b prawie nigdy nie będzie miało wartości liczbowej na końcu, to jest to rozsądny algorytm mieszający.