1. 程式人生 > >為什麼覆蓋equals方法一定要覆蓋hashCode方法

為什麼覆蓋equals方法一定要覆蓋hashCode方法

兩個物件值相同(x.equals(y) == true),但卻可有不同的hash code,這句話對不對? 
兩個物件有相同的hash code,但是值不同(x.equals(y) == false),這句話對不對? 
對,hash code相同,說明value在同一個bucket裡面,也可以說是hash衝突,x.equals(y)為true說明x和y是同一個業務物件,x.equals(y)為false說明不是同一個業務物件,產生了hash衝突。所以如果x.equals(y)==false,程式設計師應該知道,給不相同的x和y物件產生截然不同的hash code,有可能提高散列表(hash table)的效能。 
因為如果只覆蓋了equals而沒有覆蓋hashCode, 則兩個不同的instance a和b雖然equals結果(業務邏輯上)相等,但卻會有不同的hashcode,這樣hashmap裡面會同時存在a和b,而實際上我們需要hashmap裡面只能儲存其中一個,因為從業務邏輯方向看它們是相等的. 

為了能讓集合框架中的類如HashMap正常工作,必須保證同時覆蓋equals()和hashCode(),而且注意不要由於寫錯了引數型別,而過載了這兩個方法,卻並沒有覆蓋它們,比如: 
public boolean equals(Object obj) 寫成了public boolean equals(ClassXXX obj) 。 

為什麼在覆蓋equals時一定也要覆蓋hashCode呢? 下面用HashMap來闡述原因,首先假設key1和key2的值在業務邏輯領域是相等的,即它們應該是同一個物件,HashMap已經儲存了key1,現在要查詢key2是否存在,正確的結果應該是存在: 
Java中的HashMap實際上是一個連結串列陣列,即首先HashMap是一個數組,然後陣列中的每一個元素是一個連結串列(更通用的概念可以稱為桶bucket,Java中的HashMap用Entry類描述連結串列的結點結構),HashMap在執行Put,Contains之類的操作時,會首先根據你提供的Key計算hashCode值,然後根據這個hashCode值在陣列中找到某一個連結串列或桶(通常是找到連結串列的起始結點),這一步操作利用了hashCode()方法,如果你覆蓋了就會用你提供的方法,在找到某一個連結串列的起始結點後,就會遍歷連結串列,然後通過equals方法來尋找是否存在與Key的值相等的結點,如果執行equals方法後的結果相等,HashMap就認為已經存在這個元素,這一步如果你覆蓋了equals方法就會用到你提供的equals方法。 
通過上面的描述,我們發現equals方法和hashCode方法如果不同時按你自己邏輯覆蓋的話,HashMap就會出問題。比如你只覆蓋了equals方法而沒有覆蓋hashCode方法,那麼HashMap在第一步尋找連結串列的時候會出錯,有同樣值的兩個物件Key1和Key2並不會指向同一個連結串列或桶,因為你沒有提供自己的hashCode方法,那麼就會使用Object的hashCode方法,該方法是根據記憶體地址來比較兩個物件是否一致,由於Key1和Key2有不桶的記憶體地址,所以會指向不同的連結串列,這樣HashMap會認為key2不存在,雖然我們期望Key1和Key2是同一個物件;反之如果只覆蓋了hashCode方法而沒有覆蓋equals方法,那麼雖然第一步操作會使Key1和Key2找到同一個連結串列,但是由於equals沒有覆蓋,那麼在遍歷連結串列的元素時,key1.equals(key2)也會失敗(事實上Object的equals方法也是比較記憶體地址),從而HashMap認為不存在Key2物件,這同樣也是不正確的。 

以下內容摘自<<Effective Java>> 
覆蓋equals時總要覆蓋hashCode,一個很常見的錯誤根源在沒有覆蓋hashCode方法。在每個覆蓋了equals方法的類中,也必須覆蓋hashCode方法。如果不這樣做的話,就會違反Object.hashCode的通用約定,從而導致該類無法結合所有基於雜湊的集合一起正常工作,這樣的集合包括HashMap、HashSet和Hashtable。 

下面是約定的內容,摘自Object規範[JavaSE6]: 
1)在應用程式的執行期間,只要物件的equals方法所用到的資訊沒有被修改,那麼對這同一個物件呼叫多次,hashCode方法都必須始終如一地返回同一個整數。在同一個應用程式的多次執行過程中,每次執行所返回的整數可以不一致。 

2)如果兩個物件根據equals(Object)方法比較是相等的,那麼呼叫這兩個物件中任意一個物件的hashCode方法都必須產生同樣的整數結果。 

3)如果兩個物件根據equals(Object)方法比較是不相等的,那麼呼叫這兩個物件中的任意一個物件的hashCode方法,則不一定要產生不同的整數結果。但是程式設計師應該知道,給不相同的物件產生截然不同的整數結果,有可能提高散列表(hash table)的效能。 

如果覆蓋equals沒有覆蓋hashCode,將會違反上面的第2條:相等的物件必須具有相等的雜湊碼(hashCode)。Object類裡面的預設eqals方法是比較記憶體地址是否相等,預設的hashCode方法則是根據記憶體地址產生一個整數,所以Object類本身當然是符合上面規則的。當你覆蓋了equals後,記憶體地址不同的物件可能會相等,而如果這時你沒有覆蓋hashCode方法的話,hashCode還是根據記憶體地址來生成,就會出現相等的物件具有不同的雜湊碼的情況。 

下面給出了一個過載equals和hashCode的樣本:

相關推薦

為什麼覆蓋equals方法一定覆蓋hashCode方法

兩個物件值相同(x.equals(y) == true),但卻可有不同的hash code,這句話對不對?  兩個物件有相同的hash code,但是值不同(x.equals(y) == false),這句話對不對?  對,hash code相同,說明value在同一個bucket裡面,也可以說是hash衝突

為什麼重寫equals方法一定重寫HashCode方法?(

使用HashMap,如果key是自定義的類,就必須重寫hashcode()和equals()。     1.hashcode()和equals()是在哪裡被用到的?什麼用的?      HashMap是基於雜湊函式,以陣列和連結串列的方式實現的。  而對於每一個物件,通過其hashCode()方法可為其生成一

Java--什麼時候需要重寫equals方法?為什麼重寫equals方法一定重寫HashCode方法

何時需要重寫equals() 當一個類有自己特有的“邏輯相等”概念(不同於物件身份的概念)。 設計equals() [1]使用instanceof操作符檢查“實參是否為正確的型別”。 [2]對於類中的每一個“關鍵域”,檢查實參中

為什麼重寫了equals方法一定重寫hashcode方法

重寫了equals方法一定要重寫hashcode方法,原因在於用到hash來提高效率的集合類在插入物件時先比較物件的hashcode是否相同,若相同再比較equals是否相同,若hashcode不同j就不再比較equals。 雜湊表這個資料結構想必大多數人都不陌生,而且

【Java基礎之重寫equalshashCode和compareTo方法】什麼時候需要重寫重寫equals方法?為什麼重寫equals方法一定重寫HashCode方法

1.何時需要重寫equals() 當一個類有自己特有的“邏輯相等”概念(不同於物件身份的概念)。 2.設計equals() [1]使用instanceof操作符檢查“實參是否為正確的型別”。 [2]對於類中的每一個“關鍵域”,檢查實參中的域與當前物件中對應的域值。 [2

覆蓋equals時總覆蓋hashCode

覆蓋 方法 優化 equal 出現問題 相等 equals() 一個 相同 Object條約規定:相等的對象必須具有相同的散列碼hashCode 假如將只覆蓋equals方法,沒覆蓋hashCode方法的類用於HashMap中,將會出現問題,會出現get()方法返回時不是同

effectiveJava(7)覆蓋equals時總覆蓋hashcode

應用 作用 java cti object effective hashmap 產生 提高 在每個覆蓋了equals方法的類中,也必須要覆蓋hashcode方法。如果不這樣做的話,就會違反Object.hashcode的通用約定,從而導致該類無法結合所有基於散列的集合一

java中重寫equals方法為什麼重寫hashcode方法

參考博文:https://www.cnblogs.com/dolphin0520/p/3681042.html hashcode方法作用 hashcode方法是Object類的本地方法,public native int hashcode(); Java中hashcode方法主要用於雜湊

讀書筆記-《Effective Java》第9條:覆蓋equals時總覆蓋hashCode

如果覆蓋equals方法卻不覆蓋hashCode方法,那麼就很有可能出現兩個物件equals方法返回true,但hashCode卻不一致的情況,例如:在HashMap中取不到正確的value。 HashMap的get方法是用hashCode匹配的。 public V get(Obje

JAVA中重寫equals()方法為什麼重寫hashcode()方法?

object物件中的 public boolean equals(Object obj),對於任何非空引用值 x 和 y,當且僅當 x 和 y 引用同一個物件時,此方法才返回 true; 注意:當此方法被重寫時,通常有必要重寫 hashCode 方法,以維護 hashCo

覆蓋(不是過載)了equals方法,請一定覆蓋hashCode方法

為了能讓集合框架中的類如HashMap正常工作,必須保證同時覆蓋equals()和hashCode(),而且注意不要由於寫錯了引數型別,而過載了這兩個方法,卻並沒有覆蓋它們,比如:  public boolean equals(Object obj) 寫成了public boolean equals(Cla

9. 【對於所有物件都通用的方法】重寫equals方法一定重寫hashCode方法

本文是《Effective Java》讀書筆記第9條,其中內容可能會結合實際應用情況或參考其他資料進行補充或調整。 在每個覆蓋了equals方法的類中,一定也要覆蓋hasCode方法。否則會導致該類無法結合所有基於雜湊的集合(比如HashMap、HashS

JAVA中重寫equals()方法的同時重寫hashcode()方法

內存地址 his mov bool args 變量 維護 log obj object對象中的 public boolean equals(Object obj),對於任何非空引用值 x 和 y,當且僅當 x 和 y 引用同一個對象時,此方法才返回 true;註意:當此方法

【java基礎】重寫equals()方法的同時重寫hashCode()方法

而且 通過 才會 默認 什麽 需要 現在 ash 字段 1、 為什麽要重寫equals方法? 因為Object的equal方法默認是兩個對象的引用的比較,意思就是指向同一內存,地址則相等,否則不相等;如果你現在需要利用對象裏面字段的值來判斷是否相等,則重寫equals方法。

Effective Java 第三版讀書筆記——條款11:重寫 equals 方法的同時也重寫 hashCode 方法

在每一個重寫 equals 方法的類中,都要重寫 hashCode 方法。如果不這樣做,你的類會違反 hashCode 的通用約定,這會阻止它在 HashMap 和 HashSet 這樣的集合中正常工作。下面是根據 Object 原始碼改編的約定: 在一個應用程式執行過程中,如果在 equal

java中重寫equals()方法的時候為什麼重寫hashCode()方法

有時候,或許會聽到被人說,在重寫equals方法的時候,記得重寫hashcode方法。那麼自然有這樣的疑問,那麼為什麼這樣?equals方法和hashCode方法是什麼關係?不重寫的時候會有什麼危害?文章將從一下幾個方面進行敘述。 一:什麼是hashCode(),equa

Java中複寫equals 方法的同時也複寫hashCode 方法

                object物件中的 public boolean equals(Object obj),對於任何

關於為什麼重寫hashCode()方法equals()方法及如何重寫

我想寫的問題有三個: 1、首先我們為什麼需要重寫hashCode()方法和equals()方法 2、在什麼情況下需要重寫hashCode()方法和equals()方法 3、如何重寫這兩個方法 ************************************

為什麽重寫equals()方法就必須重寫hashCode()方法

shc 依然 為什麽 出現 pos 性能 導致 clas 什麽 hashCode()和equals()保持一致,如果equals方法返回true,那麽兩個對象的hasCode()返回值必須一樣。如果equals方法返回false,hashcode可以不一樣,但是這樣不利於哈