1. 程式人生 > 其它 >list集合去重_談談Java中Set集合去重的原理

list集合去重_談談Java中Set集合去重的原理

來自:https://blog.csdn.net/weixin_39527768/article/details/110826637

=======================================================================

導讀:Java中Set介面是Collectio的子介面,Set集合不允許包含相同的元素。如果新增相同的元素, add()會返回FALSE, 新元素不會加入。Set集合常用於元素為數字、字串去重等,但是當元素為自定義物件型別時,Set去重是否與我們預計一致?下面將以HashSet為例,通過一系列試驗來一步步驗證。

 

1、先建立一個FootBallPlayer足球運動員類

2、(假設:HashSet會把屬性值全相同的物件認定為重複),為了測試HashSet對物件去重效果與猜想是否一致,我們先構建三個物件例項,其中構造兩個屬性一致的“C羅”。

結果:HashSet並沒有認定兩個“C羅”物件重複,三個例項都加入到了HashSet集合中。

3、在瞭解HashSet如何進行去重之前,先看看HashSet是怎麼實現的。通過檢視JDK原始碼發現HashSet內部其實是對HashMap進行操作。

4、繼續檢視hashSet的add()方法,其實是呼叫了HashMap的put()方法

5、繼續追蹤,直到putVal()方法(重點)

仔細看putVal()方法,發現其對於新入的元素是否重複判斷依據為以下兩種

  • 判斷hash值是否相等,既通過判斷hashCode()方法
  • 判斷是否相等,通過equals()方法

6、瞭解了兩個判斷條件後,我們先做一個簡單實驗,既呼叫Integer 、String 、Object等物件equals()方法進行對比

結果發現,自定義Object物件equals返回的值為false。接下來我們逐一看看它們的equals實現方式

6.1、Integer物件的equals實現,通過閱讀程式碼發現是判斷依據是值是否相等。

6.2、String物件的equals實現,其判斷的依據為:先判斷引用的物件是否是同一個,再逐個對比其字串的值

6.3 而Object的判斷依據為引用的物件是否是同一個,由於上面的兩位足球運動員都是新new出來的,非同一個物件,所以equlas()返回結果為false

7、看完了equlas的實現,接下來看看Integer String Object的hashCode實現。同樣先做一個簡單的測試,呼叫它們的hashCode()方法計算出hash值進行對比

實驗為結果兩個Object物件的hash值並不相等,接下來我們看看它們對於hashcode()的具體實現

7.1 通過原始碼發現 Integer是通過對其value值來進運算行得到hash值。

7.2 String也是通過對其value值來進計算行得到hash值,所以測試中結果為true

7.3 當檢視Object的hashCode()方法時發現並無具體實現,通過查閱資料得知,JDK8的預設hashCode的計算是交給C++實現的,方法是通過和當前執行緒有關的一個隨機數+三個確定值,運用Marsaglia's
xorshifschema隨機數演算法得到的一個隨機數。所以兩個不同的物件得到的hash值便不相同,測試結果也為false。(對於Object的hashCode()這裡不做深入討論,如果過深入瞭解的朋友也歡迎分享)

8、得知了HashSet是通過hashcode()與equals()來進行去重,且自定義Object物件的equals()和hashcode()實現原理,那麼要實現HashSet按照我們期望的方式,當兩個物件所有屬性的值一致時認定為同一個物件,我們可以對FootBallPlayer類的equals()和hashcode()進行重寫,程式碼如下

  • hashCode() 重寫為hash值是通過對物件所有屬性的值進行運算得出。
  • equals() 重寫為先判斷引用的物件是否是同一個,再判斷物件每一個屬性值是否相等

9、重寫完方法,我們再重新執行一開始的程式,還是同樣的三個足球運動員例項。結果與期望相同,HashSet對“C羅”物件進行了去重處理。

總結

HashSet的底層是對HashMap的操作,其去重的原理通過hashCode()與equals()方法來判斷是否重複。通過實驗發現自定義物件沒有成功去重的原因與JDK預設的Object物件hashCode()和equals()實現有關。對於自定義物件的去重,我們可以通過重寫自定義物件的hashCode()與equals()使其按照我們所想要的規則進行去重操作。

感謝您的閱讀,如果喜歡本文歡迎關注和轉發,本頭條號將堅持原創,持續分享IT技術知識。對於文章內容有其他想法或意見建議等,歡迎提出共同討論共同進步