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中都存在這一問題!