2012-11-03 32 views
4

在java中,當我使用String作爲HashMap的鍵時,與使用字符串散列碼作爲HashMap中的鍵時的結果稍有不同。Java中的散列鍵

任何見解?

+3

你能更具體嗎?在你面臨這個問題的地方顯示一些代碼片段。 –

+0

爲什麼你期待一個不同的關鍵產生相同的結果?它不會。 – EJP

回答

11

當我使用字符串散列碼作爲HashMap中的鍵。

絕不能使用散列碼本身作爲關鍵。哈希代碼並不是唯一的 - 完全允許兩個不相等的值具有相同的哈希代碼。您應該使用字符串本身作爲關鍵。然後地圖將首先比較散列碼(快速縮小候選匹配),然後與equals比較正品字符串相等。

當然,這是假設你的代碼真的是你的問題,例如,

HashMap<String, String> goodMap = new HashMap<String, String>(); 
goodMap.put("foo", "bar"); 

HashMap<Integer, String> badMap = new HashMap<Integer, String>(); 
badMap.put("foo".hashCode(), "bar"); 

如果這真是你的代碼是什麼樣子,只是使用HashMap<String, String>代替。

從文檔爲Object.hashCode()(重點煤礦):

hashCode的一般合同是:

  • 每當它是一個Java的執行期間,在同一對象不止一次調用應用程序中,只要修改了對象的等號比較中使用的信息,hashCode方法就必須始終返回相同的整數。該整數不需要從應用程序的一次執行到同一應用程序的另一次執行保持一致。
  • 如果兩個對象根據equals(Object)方法相等,則對這兩個對象中的每個對象調用hashCode方法必須產生相同的整數結果。
  • 根據equals(java.lang.Object)方法,如果兩個對象不相等,則不要求對這兩個對象中的每個對象調用hashCode方法必須產生不同的整數結果。但是,程序員應該意識到,爲不等對象生成不同的整數結果可能會提高散列表的性能。
3

當然。不同的字符串可以有相同的hashCode,所以如果你在地圖中存儲兩個這樣的字符串作爲鍵,你將有兩個條目(因爲字符串不同)。 Whareas如果使用他們的hashCode作爲關鍵字,那麼只會有一個條目(因爲它們的hashCode是相同的)。

hashCode不用於判斷兩個鍵是否相等。它僅用於將密鑰分配給一個存儲桶。一旦找到桶,桶中包含的每個密鑰將與等於的新密鑰進行比較,如果找不到相同的密鑰,則會將密鑰添加到桶中。

+0

感謝所有的答案。我試圖避免將密鑰存儲爲字符串,因爲它會消耗更多的內存! – user1785771

+0

不要在沒有測量的情況下跳到這個結論。爲什麼會使用更多的內存?地圖不會複製密鑰。它只是使用對密鑰的引用。 –

+0

我知道。但是,當我有超過兩百萬條記錄,然後存儲他們的字符串鍵會有很大的不同! @JB – user1785771

3

問題是,即使兩個對象不同,並不意味着它們的哈希碼也不同。

兩個不同的對象可以共享相同的哈希碼。所以,你不應該把它們當作一個HashMap鍵。

另外,由於從Object.hashCode()方法返回的散列碼的類型爲int,因此只能有2^32不同的值。這就是爲什麼你會因爲不同的對象而產生「碰撞」,這取決於哈希算法。

簡而言之: -

!obj.equals(obj1)不保證obj.hashCode() != obj1.hashCode()

+0

我會在最後一行使用'!obj.equals(obj1)',因爲這是最重要的部分。 –

+0

@JonSkeet。是啊,沒錯。編輯。謝謝 :) –

1

HashCodes對於相同的字符串可以相同或不同,所以要小心。可能這就是你得到不同結果的原因。

這是another SO question就可以了。見Jon Skeet接受的答案。

0

可以使用的哈希碼僅如果散列函數是一個完美的哈希鍵(見例如GPERF)。只要你的關鍵對象不駐留在內存中,你是正確的,你將節省內存。