2010-10-06 30 views
8

有時我需要通過組合其多個實例成員的hashCode來實現obj的hashCode()方法。例如,如果組合的obj擁有成員,B和C,我經常看到PPL實現它作爲實現hashCode()的首選方式是什麼?


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

來自哪裏這個神奇的數字31?它是4字節的長度還是隻是一個素數?

是否有任何其他的首選/標準方式實現hashCode()?

+0

類似(但不一定重複):http://stackoverflow.com/questions/3613102/why-use-a-prime-number-in-hashcode – 2010-10-06 03:24:13

+0

質量31用於String.hashCode()這使得一個好的素數,因爲沒有太多可能的角色,但是我傾向於使用更大的素數。因爲我只是無恥地引用了布洛赫,所以「有趣」素數的好網站是http://primes.utm.edu/curios/ – 2010-10-06 05:57:58

回答

8

請參閱Effective Java's recipe。這只是最好的來源,請放心。

素數的使用只是爲了在不知道域的情況下獲得合理的分佈。溢出到相同的值將需要一段時間。如果我記得正確,值31是相當隨意的。

根據布洛赫(他使用17作爲初始值和37作爲恆定乘數):

非零初始值被使用(...),所以該散列值通過將初始 影響哈希值(...)爲零的字段。如果使用零作爲 ,則初始值(...)整體散列值將不受任何此類初始字段的影響,這可能會增加衝突。值17是任意的。
...
選擇乘數37是因爲它是一個奇素數。如果是偶數並且乘法溢出,則信息將會丟失,因爲乘以 等於移位。使用質數的好處不在於明確,但爲此目的使用質數是傳統的。

+0

CW。 – 2010-10-06 03:15:36

+4

在Effective Java的第二版中,Josh Bloch使用了31而不是37.他解釋了這個選擇:「31的一個很好的性質是乘法可以被替換爲移位和減法以獲得更好的性能:'31 * i = =(i << 5) - i'。現代虛擬機自動完成這種優化。「 – ColinD 2010-10-06 03:46:54

2

使用HashCodeBuilder從下議院郎鹹平:

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

請參閱如何做到這一點,而無需使用反射API。您可以告訴它要包含哪些字段或要忽略哪些字段。

另請參見EqualsBuilder,用於重寫equals方法。

6

一個不錯的選擇是GuavaObjects.hashCode方法。它需要的任何數量的參數,並創建基於它們的哈希碼:

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

基本上,你的散列碼應該由你的POJO的關鍵參數。一個例子如下。

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

在上面的例子中,roll id和name是該POJO的關鍵參數。

如果您僅將這些參數添加到您在同一POJO的Eqauls方法中添加的hashCode方法中,這是一種很好的做法。

1

使用IDE生成它。

0

我相信以下是簡單場景的良好實踐: 如果您的類包含任何只讀成員,那麼它們將是生成對象哈希碼的理想選擇。 但是,如果您的類只包含變異成員,則可以創建一個只讀int字段,該字段根據傳遞給構造函數的非空值獲取該值。

相關問題