為什麼在重寫 equals 方法的時候需要重寫 hashCode 方法
因為有強制的規範指定需要同時重寫 hashcode 與 equals 方法,許多容器類,如 HashMap、HashSet 都依賴於 hashcode 與 equals 的規定。
在Java中,equals()
和 hashCode()
方法是 Object
類的兩個非常重要的方法,它們用於比較物件的相等性以及計算物件的雜湊碼。
equals()
方法用於判斷兩個物件是否邏輯上相等,也就是兩個物件的內容是否相同。它通常需要根據實際情況在子類中重寫,以提供正確的相等性邏輯。預設情況下(如 Object 類中的實現),equals()
方法比較物件的記憶體地址,也就是說,只有同一個物件才被認為是相等的。
hashCode()
方法則用於計算物件的雜湊碼,它被用於雜湊資料結構,如 HashSet
、HashMap
等。在雜湊資料結構中,物件的雜湊碼通常被用來決定物件應該存放的位置。
根據 Java 規範,有關 equals()
和 hashCode()
的重要契約包括:
- 如果兩個物件相等,那麼它們的
hashCode()
方法必須返回相同的整數。 - 如果兩個物件的
hashCode()
方法返回相同的整數,這並不要求它們一定相等,但雜湊表的效率可能受到影響。
之所以在重寫 equals()
方法時必須同時重寫 hashCode()
方法,是為了維持這兩個方法之間的一致性。如果兩個物件是相等的,但它們的雜湊碼不相同,這將違反 hashCode()
方法的契約,可能導致無法正確地存取雜湊資料結構中的物件。例如,在使用 HashMap
時,如果兩個鍵物件相等,它們必須具有相同的雜湊碼,否則可能會導致其中一個物件無法被正確地找到。
有沒有可能兩個不相等的物件有相同的 hashcode?
有可能,即使兩個物件不相同,它們也可能具有相同的 hashCode
值,這稱為雜湊衝突。雜湊衝突是雜湊演算法的一個固有屬性,因為雜湊碼是將物件資訊對映到一個有限的整數域上。由於這個整數域範圍的限制,相對於可能的物件狀態來說是不足夠的,從而導致不同物件間的雜湊值可能相同。
Java語言規範中關於 hashCode
的合同確實指出,如果兩個物件相同,則它們的雜湊碼一定相同,但並未規定不同的物件必須產生不同的雜湊碼。因此,在基於雜湊的資料結構中,如 HashMap
,便可能出現雜湊碰撞。在這種情況下,HashMap
會使用 連結串列
或 紅黑樹
來管理相同雜湊碼的不同鍵,確保了即便發生了雜湊碰撞,也能透過 equals()
方法準確地區分和處理這些鍵。
因此,為了確保諸如 HashMap
、HashSet
這樣的基於雜湊的集合能夠正確且高效地運作,合理地實現 hashCode
和 equals
方法以及妥善處理雜湊衝突是至關重要的。
兩個相同的物件會有不同的 hash code 嗎?
不能,根據 hash code 的規定,這是不可能的。
在 Java 中,當你重寫一個類的 equals()
方法時,根據 Java 的規範,你也必須重寫 hashCode()
方法,以保證同一個類的兩個相等的物件(即 equals()
方法返回 true
)返回相同的 hash code 值。這是因為 Java 中的集合類,如 HashMap
和 HashSet
,依賴於 hashCode()
和 equals()
方法來確定物件的唯一性。
如果兩個物件根據 equals(Object)
方法是相等的,那麼它們的 hashCode()
方 法也必須返回相同的整數值。如果沒有重寫 hashCode()
,那麼預設的 Object
類的實現將產生基於物件記憶體地址的 hash code,這可能會違反這一規定,並且在使用雜湊表的過程中導致效能下降。所以重寫 equals()
時一定要同步重寫 hashCode()
,以確保行為的一致性。