Java覆寫equals方法必須覆寫hashCode方法
研發說 · 程式 ·

Java覆寫equals方法必須覆寫hashCode方法

覆寫equals方法必須覆寫hasCode方法,這條規則基本上每個Javaer都知道,這也是JDK的API上反覆說明的,不過為什麼要則這麼做呢?這兩個方法之間什麼關係呢?本建議就來解釋該問題,我們先看看代碼:

public class Client48 { public static void main(String[] args) { // Person類的實例作為map的key Map<Person, Object> map = new HashMap<Person, Object>() { { put(new Person("張三"), new Object()); } }; // Person類的實例作為List的元素 List<Person> list = new ArrayList<Person>() { { add(new Person("張三")); } }; boolean b1 = list.contains(new Person("張三")); boolean b2 = map.containsKey(new Person("張三")); System.out.println(b1); System.out.println(b2); }}
這麼做呢?這兩個方法之間什麼關係呢?本建議就來解釋該問題,我們先看看代碼

  代碼中的Person類與上一建議的Person相同,equals方法完美無缺。在這段代碼中,我們在聲明時直接調用方法賦值,這其實也是一個內部匿名類,現在的問題是b1和b2值是否都為true?

  我們先來看b1,Person類的equals覆寫了,不再判斷兩個地址相等,而是根據人員的姓名來判斷兩個對象是否相等,所以不管我們的new Person("張三")產生了多少個對象,它們都是相等的。把張三放入List中,再檢查List中是否包含,那結果肯定是true了。

  接下來看b2,我們把張三這個對象作為了Map的鍵(Key),放進去的是張三,檢查的對象還是張三,那應該和List的結果相同了,但是很遺憾,結果為false。原因何在呢?

  原因就是HashMap的底層處理機制是以數組的方式保存Map條目的(Map Entry)的,這其中的關鍵是這個數組的下標處理機制:依據傳入元素HashCode方法的返回值決定其數組的下標,如果該數組位置上已經有Map條目,並且與傳入的值相等則不處理,若不相等則覆蓋;如果數組位置沒有條目,則插入,並加入到Map條目的鍊表中。同理,檢查鍵是否存在也是根據哈希碼確定位置,然後遍歷查找鍵值的。

  接著深入探討,那對象元素的hashCode方法返回的是什麼值呢?它是一個對象的哈希碼,是由Object類的本地方法生成的,確保每個對象有一個哈希碼(也是哈希算法的基本要求:任意輸入k,通過一定算法f(k),將其轉換為非可逆的輸出,對於兩個輸入k1和k2,要求若k1=k2,則必須f(k1)=f(k2),但也允許k1 != k2 , f(k1)=f(k2)的情況存在)。

  那回到我們的例子上,由於我們沒有覆寫hashCode方法,兩個張三對象的hashCode方法返回值(也就是哈希碼)肯定是不相同的了,在HashMap的數組中也找不到對應的Map條目了,於是就返回了false。

  問題清楚了,修改也很簡單,在Person類中重寫一下hashCode方法即可,代碼如下: 

每個Javaer都知道,這也是JDK的API上反覆說明的,不過為什麼要則
class Person{ @Override public int hashCode() { return new HashCodeBuilder().append(name).toHashCode(); } }
覆寫equals方法必須覆寫hasCode方法,這條規則基本上

  其中HashCodeBuilder是org.apache.commons.lang.builder包下的一個哈希碼生成工具,使用起來非常方便,大家可以直接項目中集成(為何不直接寫hashCode方法?因為哈希碼的生成有很多種算法,自己寫麻煩,事兒又多,所以必要的時候才取"拿來主義",不重複造輪子是最好的辦法。)

聲明:文章觀點僅代表作者本人,PTTZH僅提供信息發布平台存儲空間服務。
喔!快樂的時光竟然這麼快就過⋯
繼續其他精彩內容吧!
more