個人博客網:https://wushaopei.github.io/ (你想要這里多有)
眾所周知,HashSet 的值是不可能被重復的,在業務上經常被用來做數據去重的操作,那么,其內部究竟是怎么保證元素不重復的呢?
這里將對HashSet 的源碼進行逐步的解析:
當我們對一個HashSet 的實例添加一個值時,使用到的是它的 add 方法,源碼如下:
由以上的add 方法內的實現可知,其維護了一個 HashMap 來實現元素的添加;眾所周知,HashMap 作為雙列集合,它的鍵是不能夠重復的,這里的 PRESENT 是作為占位符的存在,與值重復判斷與否沒有意義,不作贅述。
其實,到了這里,我們已經可以知道 HashSet 的值作為 HashMap 中的 key(鍵)的,可以確定是不會存在重復值存在的情況發生。
但是,我們要了解的是為什么不會重復,繼續深究,這里繼續了解對該值的一個不可重復的原因.
以下是HashSet 引用HashMap的具體位置。
HashSet 其實是在構造器內實例化了一個 HashMap 對象,那么可以得知,HashSet 的值不可重復是依賴於 HashMap 的底層對值不可重復的依賴。
其實
以下我們進入到 HashMap 的 put()方法中去:
由 put 方法的實現可知,該 put 方法對傳入的 Map 的key - value 進行了更深一層的 putVal()的處理。
但這個方法不是我們現在需要了解的,稍后再對這里進行了解。
進入 putVal() 方法之前,對傳入的 key 進行了hash 運算,獲取了一個 hash 值:
獲取hash 值的規則是 :當 key == null 時,hash 值為0;若不為null,則說明值有效,會通過 hashCode()
關於 hashCode() 在這里的作用:
hashCode在上面扮演的角色為尋域(尋找某個對象在集合中區域位置)。hashCode可以將集合分成若干個區域,每個對象都可以計算出他們的hash碼,可以將hash碼分組,每個分組對應着某個存儲區域,根據一個對象的hash碼就可以確定該對象所存儲區域,這樣就大大減少查詢匹配元素的數量,提高了查詢效率。
關於Key 不能夠重復,這里可以得出了,相同的值得到的 hash 碼大概率上是相同的,所以,key 可以保證不會重復,因為重復的值,一定會被覆蓋。具體從后面的源碼繼續看:
注意 以上方法 中的這一句:
由此可知,HashMap 的 集合元素 key-value 添加時,這里調用了對象的hashCode和equals方法進行的判斷。
但要注意,原生的 hashCode 和 equals 更多的是在引用的位置上進行了去重校驗,如要對具體的值或對象本身進行去重,還需進行重寫操作。
所以又得出一個結論:若要將對象存放到HashSet中並保證對象不重復,應根據實際情況將對象的hashCode方法和equals方法進行重寫