HashSet集合中hashCode及equals方法詳解

  • 2019 年 12 月 8 日
  • 筆記

首先我們熟知HashSet集合中元素存儲的特點:

1)不允許元素重複

2)不會記錄元素添加的先後順序

3)HashSet中比較兩個對象是否相同,要使用equals()方法,不能使用 ==;

4)底層依然使用哈希表(散列)演算法,其本質就是數組形式,採用此演算法就為提高查詢的效率;

5)插入速度也比較快,但適合於少量元素插入操作;一旦所存儲元素個數滿足(size * loadFoctor > size),哈希表就要擴容,此時操作速度極慢,性能就會降低!

由於HashSet集合中的元素不能重複存儲,那應該怎樣做呢?

1)先判斷兩個對象的hashCode()方法返回值是否相同,即存儲的位置;

2)然後再判斷兩個對象的equals()方法返回值是否為true,即存儲實際的對象值。

接下來我們就來講解一下採用哈希表(散列)演算法實現元素不可重複存儲,具體的思想:

第一:

1)Set集合中元素沒有順序,不能重複;

2)元素重複是指:存儲對象的重複;

3)何為對象的重複:記憶體中,所在記憶體編號一致(相同);

4)記憶體編號表示:哈希碼值(哈希碼值一般是  類名  和  對象所在記憶體地址的十六進位數字表示的集合)

第二:(現實共同觀念)

現實生活中只要屬性相同,我們就認為這兩個對象就是同一個對象,但這與電腦比較同一個對象的方法不同(電腦使用記憶體地址,即哈希碼值);Object類中的hashCode()方法是不可能返回兩個相同的哈希碼值(一個哈希碼值唯一的標誌了一個對象),即地址的唯一性。但是這樣就不能讓程式的運行符合現實生活(現實邏輯:屬性相同的對象被看作是同一個對象)

於是就需要重寫equals()和hashCode()方法,並且基本數據類型都重寫了這兩個方法!

第三:

重寫這兩個方法有什麼用呢?

主要目的:屬性相同的兩個對象,返回的哈希碼值是相同的!

程式向HashSet集合中添加一個元素時,先調用對象的hashCode()方法計算出該對象的哈希碼值;

比較:

(1)如果該對象與集合中所存儲的全部對象的哈希碼值不一致,則該對象就不重複,計算出該對象在哈希表中的索引位置,直接添加;

(2)如果該對象與集合中存儲的某一對象哈希碼值一致(重碼現象),那就需要通過equals()方法判斷相同哈希碼值的對象是否為同一對象(判斷標準:屬性是否相同);

a)相同對象,新值覆蓋舊值;

b)不相同,在該索引位置,以頭插的形式插入鏈表中。

第四:有兩個疑問

(1)為什麼哈希碼值相同了,還有可能是不同的對象?

雖然重寫hashCode()方法的主要目的:屬性相同的兩個對象,返回的哈希碼值是相同的!

但是在重寫hashCode()方法時,幾乎所有的寫法都無法避免一個bug:有一些對象(當然是不同的對象),會返回相同的哈希碼(即重碼),此時就需要藉助equals()方法;

在哈希碼相同的情況下,再使用equals()方法判斷兩個對象的屬相是否一樣,就可以做到萬無一失了

(2)為什麼經過比較哈希碼值,還需要藉助equals()方法判斷呢?

HashSet集合底層採用了哈希演算法實現,多個不同的對象可能返回的哈希碼值不同,但是通過計算得到的哈希表中的索引位置相同,這樣就再次需要通過equals()方法來判斷這兩個對象的屬性值是否相同,比較完再做相應的處理!

總思路:哈希碼不同時,則必為不同的對象,重寫hashCode()方法時,哈希碼相同(可能出現重碼現象),則根據euqals()方法判斷是否新值覆蓋舊值;兩者都是以鏈表頭插方式!在HashSet、HashMap、HashTable中都存在這一問題!