本篇內(nèi)容介紹了“Java中HashSet集合怎么對(duì)自定義對(duì)象進(jìn)行去重”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
創(chuàng)新互聯(lián)是一家專注于成都網(wǎng)站建設(shè)、成都做網(wǎng)站與策劃設(shè)計(jì),橋西網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)做網(wǎng)站,專注于網(wǎng)站建設(shè)十多年,網(wǎng)設(shè)計(jì)領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:橋西等地區(qū)。橋西做網(wǎng)站價(jià)格咨詢:028-86922220
Java中Set接口是Collectio的子接口,Set集合不允許包含相同的元素。如果添加相同的元素, add()會(huì)返回FALSE, 新元素不會(huì)加入。Set集合常用于元素為數(shù)字、字符串去重等,但是當(dāng)元素為自定義對(duì)象類型時(shí),Set去重是否與我們預(yù)計(jì)一致?下面將以HashSet為例,通過(guò)一系列試驗(yàn)來(lái)一步步驗(yàn)證。
1. 先建立一個(gè)FootBallPlayer足球運(yùn)動(dòng)員類
2. (假設(shè):HashSet會(huì)把屬性值全相同的對(duì)象認(rèn)定為重復(fù)),為了測(cè)試HashSet對(duì)對(duì)象去重效果與猜想是否一致,我們先構(gòu)建三個(gè)對(duì)象實(shí)例,其中構(gòu)造兩個(gè)屬性一致的“C羅”。
結(jié)果:HashSet并沒(méi)有認(rèn)定兩個(gè)“C羅”對(duì)象重復(fù),三個(gè)實(shí)例都加入到了HashSet集合中。
3. 在了解HashSet如何進(jìn)行去重之前,先看看HashSet是怎么實(shí)現(xiàn)的。通過(guò)查看JDK源碼發(fā)現(xiàn)HashSet內(nèi)部其實(shí)是對(duì)HashMap進(jìn)行操作。
4. 繼續(xù)查看hashSet的add()方法,其實(shí)是調(diào)用了HashMap的put()方法
5. 繼續(xù)追蹤,直到putVal()方法(重點(diǎn))
仔細(xì)看putVal()方法,發(fā)現(xiàn)其對(duì)于新入的元素是否重復(fù)判斷依據(jù)為以下兩種
判斷hash值是否相等,既通過(guò)判斷hashCode()方法
判斷是否相等,通過(guò)equals()方法
6. 了解了兩個(gè)判斷條件后,我們先做一個(gè)簡(jiǎn)單實(shí)驗(yàn),既調(diào)用Integer 、String 、Object等對(duì)象equals()方法進(jìn)行對(duì)比
結(jié)果發(fā)現(xiàn),自定義Object對(duì)象equals返回的值為false。接下來(lái)我們逐一看看它們的equals實(shí)現(xiàn)方式
(1) Integer對(duì)象的equals實(shí)現(xiàn),通過(guò)閱讀代碼發(fā)現(xiàn)是判斷依據(jù)是值是否相等。
(2) String對(duì)象的equals實(shí)現(xiàn),其判斷的依據(jù)為:先判斷引用的對(duì)象是否是同一個(gè),再逐個(gè)對(duì)比其字符串的值
(3) 而Object的判斷依據(jù)為引用的對(duì)象是否是同一個(gè),由于上面的兩位足球運(yùn)動(dòng)員都是新new出來(lái)的,非同一個(gè)對(duì)象,所以equlas()返回結(jié)果為false
7. 看完了equlas的實(shí)現(xiàn),接下來(lái)看看Integer String Object的hashCode實(shí)現(xiàn)。同樣先做一個(gè)簡(jiǎn)單的測(cè)試,調(diào)用它們的hashCode()方法計(jì)算出hash值進(jìn)行對(duì)比
實(shí)驗(yàn)為結(jié)果兩個(gè)Object對(duì)象的hash值并不相等,接下來(lái)我們看看它們對(duì)于hashcode()的具體實(shí)現(xiàn)
(1) 通過(guò)源碼發(fā)現(xiàn) Integer是通過(guò)對(duì)其value值來(lái)進(jìn)運(yùn)算行得到hash值。
(2) String也是通過(guò)對(duì)其value值來(lái)進(jìn)計(jì)算行得到hash值,所以測(cè)試中結(jié)果為true
(3) 當(dāng)查看Object的hashCode()方法時(shí)發(fā)現(xiàn)并無(wú)具體實(shí)現(xiàn),通過(guò)查閱資料得知,JDK8的默認(rèn)hashCode的計(jì)算是交給C++實(shí)現(xiàn)的,方法是通過(guò)和當(dāng)前線程有關(guān)的一個(gè)隨機(jī)數(shù)+三個(gè)確定值,運(yùn)用Marsaglia's
xorshifschema隨機(jī)數(shù)算法得到的一個(gè)隨機(jī)數(shù)。所以兩個(gè)不同的對(duì)象得到的hash值便不相同,測(cè)試結(jié)果也為false。(對(duì)于Object的hashCode()這里不做深入討論,如果過(guò)深入了解的朋友也歡迎分享)
8. 得知了HashSet是通過(guò)hashcode()與equals()來(lái)進(jìn)行去重,且自定義Object對(duì)象的equals()和hashcode()實(shí)現(xiàn)原理,那么要實(shí)現(xiàn)HashSet按照我們期望的方式,當(dāng)兩個(gè)對(duì)象所有屬性的值一致時(shí)認(rèn)定為同一個(gè)對(duì)象,我們可以對(duì)FootBallPlayer類的equals()和hashcode()進(jìn)行重寫,代碼如下
hashCode() 重寫為hash值是通過(guò)對(duì)對(duì)象所有屬性的值進(jìn)行運(yùn)算得出。
equals() 重寫為先判斷引用的對(duì)象是否是同一個(gè),再判斷對(duì)象每一個(gè)屬性值是否相等
9. 重寫完方法,我們?cè)僦匦聢?zhí)行一開始的程序,還是同樣的三個(gè)足球運(yùn)動(dòng)員實(shí)例。結(jié)果與期望相同,HashSet對(duì)“C羅”對(duì)象進(jìn)行了去重處理。
總結(jié)
HashSet的底層是對(duì)HashMap的操作,其去重的原理通過(guò)hashCode()與equals()方法來(lái)判斷是否重復(fù)。通過(guò)實(shí)驗(yàn)發(fā)現(xiàn)自定義對(duì)象沒(méi)有成功去重的原因與JDK默認(rèn)的Object對(duì)象hashCode()和equals()實(shí)現(xiàn)有關(guān)。對(duì)于自定義對(duì)象的去重,我們可以通過(guò)重寫自定義對(duì)象的hashCode()與equals()使其按照我們所想要的規(guī)則進(jìn)行去重操作。
“Java中HashSet集合怎么對(duì)自定義對(duì)象進(jìn)行去重”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!