快速提問:如果我想使用HashMap
以自定義類作爲密鑰,必須我覆蓋hashCode
函數?如果我不覆蓋該功能,它將如何工作?使用帶自定義密鑰的HashMap
回答
從技術上講,只要相等的對象具有相同的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方法結果的方式更改關鍵對象,否則地圖會贏得'找到你的價值了。這就是爲什麼建議儘可能使用不可變對象作爲鍵。
唯一不需要覆蓋hashCode()
函數的是當你也不覆蓋equals
,所以你使用默認的Object.equals
定義引用相等。這可能是也可能不是你想要的 - 特別是,不同的對象而不是即使它們具有相同的字段值也被認爲是相等的。
如果你覆蓋equals
而不是hashCode
,HashMap
行爲將是未定義的(閱讀:它根本沒有任何意義,並將完全損壞)。
如果你不重寫hashCode AND等於你會得到默認的行爲,即每個對象是不同的,不管它的內容。
它取決於您用作鍵的對象類。如果它是一個像你所建議的自定義類,並且它沒有擴展任何東西(例如它擴展了Object
),那麼hashCode函數將是Object
,並且會考慮內存引用,使得兩個對象看起來一樣哈希到不同的代碼。
所以是的,除非你正在擴展一個你認爲適合你的功能的類,否則你需要實現你自己的功能。還請確保執行equals()
:有些類像ArrayList
將只使用equals,而其他像HashMap將同時檢查hashCode()
和equals()
。
你是對的。剛剛檢查了HashMap.put()是肯定的,而且我確實錯了。謝謝!我修正了答案以反映你的評論。 – Miquel
如果不檢查實現細節,可以看到在抽象層次上,它必然是由於散列衝突的不可避免性。如果不考慮「等於」,那麼任何兩個在哈希碼上碰撞的對象最終都會相同。 –
請考慮一下,如果你的鑰匙不是不可變的,你可能會遇到問題。如果您在地圖中添加了一個可變關鍵字的條目,則您稍後更改關鍵字會影響哈希碼,並且等於您可能會丟失地圖中的條目,因爲您將無法再檢索它。
您應該覆蓋Object類中的equals()
和hashCode()
方法。從java.lang.Object
繼承的equals()
和hashcode()
的默認實現使用對象實例的內存位置(例如[email protected]
)。當一個對象的兩個實例具有相同的屬性時,這可能會導致問題,但繼承的equals()
將返回false
,因爲它使用memory location
,這對於兩個實例是不同的。
也可以重寫toString()
方法以提供對象的正確字符串表示形式。實施定義密鑰的用戶時
主要考慮
- 如果一個類重寫
equals()
,它必須重寫hashCode()
。 - 如果2個對象相等,那麼它們的
hashCode
值也必須相等。 - 如果在
equals()
中未使用某個字段,則不能在hashCode()
中使用該字段。 - 如果經常訪問,
hashCode()
是緩存提高性能的候選者。
- 1. 使用自定義密鑰解密SecureString
- 2. 帶類密鑰的Java HashMap泛型
- 3. 軌,Mongoid:使用自定義鍵和自定義密鑰格式
- 4. 如何使用我自己的密鑰安排HashMap中的現有密鑰?
- 5. 用自定義類綁定密鑰
- 6. 定義自定義Firebase密鑰
- 7. Android - 如何使用自定義密鑰(和自定義數據)將HashMap存儲到內部存儲?
- 8. 使用自定義加密密鑰的FormsAuthentication
- 9. AES自定義密碼密鑰
- 10. 帶自定義路徑的Pip,Git和ssh密鑰
- 11. iOS - 使用自定義加密密鑰保護文件?
- 12. id密鑰的自定義包裝
- 13. Android的twitter4j自定義API密鑰
- 14. EntityType'IdentityUserLogin'沒有定義密鑰。定義此EntityType的密鑰
- 15. EntityType'MyProfile'沒有定義密鑰。定義此EntityType的密鑰
- 16. 在Jetty的WebSocketClientFactory中使用自定義密鑰庫
- 17. BouncyCastle使用自定義密鑰的J2ME RSA
- 18. 如何使用Calabash-android的自定義密鑰庫?
- 19. HashMap以null作爲密鑰
- 20. Java HashMap空值或密鑰
- 21. 自定義密鑰生成在RavenDB
- 22. Google App Engine NDB自定義密鑰ID
- 23. 自定義openssl生成RSA密鑰params
- 24. Laravel:Dingo/API分頁自定義根密鑰
- 25. 使用帶有2個密鑰的重複密鑰更新
- 26. EntityType'IdentityUserLogin'沒有定義密鑰/ EntityType'IdentityUserRole'沒有定義密鑰
- 27. HashMap的:使用對象爲重點,並使用該密鑰
- 28. 基於預定義密鑰的自定義排序
- 29. 使用自定義KMS密鑰訪問AWS參數存儲值
- 30. 使用自定義密鑰激活命令行模式
除非他擴展了一個有hashCode的作品 – Miquel