2012-07-01 55 views

回答

3

從技術上講,只要相等的對象具有相同的hashCode,就不必重寫hashCode方法。

因此,如果您使用Object定義的默認行爲,其中equals僅對同一個實例返回true,那麼您不必重寫hashCode方法。

但是,如果您不覆蓋equals和hashCode方法,這意味着您必須確保始終使用相同的密鑰實例。

例如爲:

MyKey key1_1 = new MyKey("key1"); 

myMap.put(key1_1,someValue); // OK 

someValue = myMap.get(key1_1); // returns the correct value, since the same key instance has been used; 

MyKey key1_2 = new MaKey("key1"); // different key instance 

someValue = myMap.get(key1_2); // returns null, because key1_2 has a different hashCode than key1_1 and key1_1.equals(key1_2) == false 

在實踐中你經常有鑰匙的只有一個實例,所以在技術上你沒有重載equals和hashCode方法。

但最好的做法是重寫用作鍵的類的equals和hashCode方法,因爲有時候您或其他開發人員可能會忘記需要使用相同的實例,這可能導致難以跟蹤問題。

注意:即使您重寫了equals和hashCode方法,您也必須確保不會以改變equals或hashCode方法結果的方式更改關鍵對象,否則地圖會贏得'找到你的價值了。這就是爲什麼建議儘可能使用不可變對象作爲鍵。

3

唯一不需要覆蓋hashCode()函數的是當你也不覆蓋equals,所以你使用默認的Object.equals定義引用相等。這可能是也可能不是你想要的 - 特別是,不同的對象而不是即使它們具有相同的字段值也被認爲是相等的。

如果你覆蓋equals而不是hashCode,HashMap行爲將是未定義的(閱讀:它根本沒有任何意義,並將完全損壞)。

4

如果你不重寫hashCode AND等於你會得到默認的行爲,即每個對象是不同的,不管它的內容。

+2

除非他擴展了一個有hashCode的作品 – Miquel

2

它取決於您用作鍵的對象類。如果它是一個像你所建議的自定義類,並且它沒有擴展任何東西(例如它擴展了Object),那麼hashCode函數將是Object,並且會考慮內存引用,使得兩個對象看起來一樣哈希到不同的代碼。

所以是的,除非你正在擴展一個你認爲適合你的功能的類,否則你需要實現你自己的功能。還請確保執行equals():有些類像ArrayList將只使用equals,而其他像HashMap將同時檢查hashCode()equals()

+0

你是對的。剛剛檢查了HashMap.put()是肯定的,而且我確實錯了。謝謝!我修正了答案以反映你的評論。 – Miquel

+1

如果不檢查實現細節,可以看到在抽象層次上,它必然是由於散列衝突的不可避免性。如果不考慮「等於」,那麼任何兩個在哈希碼上碰撞的對象最終都會相同。 –

0

請考慮一下,如果你的鑰匙不是不可變的,你可能會遇到問題。如果您在地圖中添加了一個可變關鍵字的條目,則您稍後更改關鍵字會影響哈希碼,並且等於您可能會丟失地圖中的條目,因爲您將無法再檢索它。

0

您應該覆蓋Object類中的equals()hashCode()方法。從java.lang.Object繼承的equals()hashcode()的默認實現使用對象實例的內存位置(例如[email protected])。當一個對象的兩個實例具有相同的屬性時,這可能會導致問題,但繼承的equals()將返回false,因爲它使用memory location,這對於兩個實例是不同的。

也可以重寫toString()方法以提供對象的正確字符串表示形式。實施定義密鑰的用戶時

主要考慮

  1. 如果一個類重寫equals(),它必須重寫hashCode()
  2. 如果2個對象相等,那麼它們的hashCode值也必須相等。
  3. 如果在equals()中未使用某個字段,則不能在hashCode()中使用該字段。
  4. 如果經常訪問,hashCode()是緩存提高性能的候選者。
相關問題