關(guān)于HashSet與HashMap的區(qū)別及說明
HashSet與HashMap的區(qū)別
HashSet 集合不允許存儲相同的元素, 它底層實(shí)際上使用 HashMap 來存儲元素的,不過關(guān)注的只是key元素, 所有 value元素默認(rèn)為 Object類對象.
HashSet源碼如下
HashSet 的構(gòu)造方法
//HashSet底層用來存儲元素的結(jié)構(gòu),實(shí)際上使用HashMap來存儲 private transient HashMap<E,Object> map; //HashMap中的value值,HashSet只關(guān)注key值,所以所有的value值都為Object對象 private static final Object PRESENT = new Object(); //HashSet的無參構(gòu)造,直接創(chuàng)建了一個HashMap對象 public HashSet() { map = new HashMap<>(); } //指定初始化容量和負(fù)載因子 public HashSet(int initialCapacity, float loadFactor) { map = new HashMap<>(initialCapacity, loadFactor); } //給定初始化容量 public HashSet(int initialCapacity) { map = new HashMap<>(initialCapacity); } public HashSet(Collection<? extends E> c) { map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16)); addAll(c); }
可以看到 HashSet的構(gòu)造方法底層都是調(diào)用 HashMap的構(gòu)造方法, 所以HashSet底層實(shí)際上是使用 HashMap 來作為存儲結(jié)構(gòu).
當(dāng)使用無參構(gòu)造創(chuàng)建 HashSet對象時, 其實(shí)調(diào)用了 HashMap的無參構(gòu)造創(chuàng)建了一個 HashMap對象, 所以 HashSet 的初始化容量也為16, 負(fù)載因子也為 0.75.
再來看看 HashSet 的 add() 方法的實(shí)現(xiàn):
可以看到 HashSet 的 add() 方法底層實(shí)際也是調(diào)用了 HashMap 的 put() 方法, 這里的key為我們傳入的將要添加到 set集合中的元素, 而value值則為 PERSENT,其實(shí)就是上面分析的 HashSet類中的一個靜態(tài)字段, 默認(rèn)為 Object對象.
HashSet并不關(guān)注value元素, 只使用 HashMap來存儲 key元素, 這就使得 HashSet判斷元素相等的條件與 HashMap中 key相等的條件其實(shí)是一樣的, 兩個元素的 hashCode值相同且通過equals()方法比較返回 true.
所以HashSet應(yīng)該重寫 equals()和hashCode()方法, 兩個元素的 HashCode相同, 保證通過equals() 方法比較返回 true.
總結(jié)一下HashSet和HashMap的區(qū)別
(1)HashSet實(shí)現(xiàn)了Set接口, 僅存儲對象; HashMap實(shí)現(xiàn)了 Map接口, 存儲的是鍵值對.
(2)HashSet底層其實(shí)是用HashMap實(shí)現(xiàn)存儲的, HashSet封裝了一系列HashMap的方法. 依靠HashMap來存儲元素值,(利用hashMap的key鍵進(jìn)行存儲), 而value值默認(rèn)為Object對象. 所以HashSet也不允許出現(xiàn)重復(fù)值, 判斷標(biāo)準(zhǔn)和HashMap判斷標(biāo)準(zhǔn)相同, 兩個元素的hashCode相等并且通過equals()方法返回true.
HashSet與HashMap的關(guān)系
HashSet作為一種最簡單的java集合類,真的可以用三句話來概括一下:
第一句:存放不重復(fù)的數(shù)據(jù)。第二句:底層基于hash表實(shí)現(xiàn)。第三句:內(nèi)部基于HashMap。
這也就是說,你想要完完全全徹徹底底地把HashSet吃透,就一定要先吃透HashMap。這篇文章將帶著你從特點(diǎn)到存儲,再到最后的實(shí)現(xiàn),從源碼角度來分析一下。
認(rèn)識
HashSet其實(shí)就是一個沒有重復(fù)數(shù)據(jù)的集合,基本用法很簡單,我們直接給個例子。
以上只是列出了其最簡單的用法。下面我們看看其繼承關(guān)系。
HashSet主要繼承了三個接口Serializable、Cloneable、Set,并且實(shí)現(xiàn)了抽象類AbstractSet。
我們直接看看源碼:
學(xué)過HashMap的人應(yīng)該都知道HashMap實(shí)現(xiàn)的是Map接口,而HashSet是Set接口。
下面我們就從源碼的角度來分析一下HashSet。
源碼分析
1、參數(shù)變量
這里有個問題,那就是既然HashSet只使用到了HashMap的key,為什么不使用null來充當(dāng)HashMap的value,而使用了PRESENT這個對象呢?
答:想要深入這個問題,我們還需要深入到源碼中看看:
以上兩個是增刪方法,在add一個元素的時候,其實(shí)調(diào)用的就是map.put(e, PRESENT)==null,HashMap在put元素的時候會出現(xiàn)兩種情況:
情況一:put的元素是新的,那么map.put會發(fā)現(xiàn)key沒有,那么直接插入即可。return結(jié)果為true。
情況二:put的元素是舊的,那么map.put會發(fā)現(xiàn)key已有,則直接返回相應(yīng)的value,也就是PRESENT,PRESENT不等于null,return的也就是false了,表示HashSet插入失敗。如果我們這里使用null為map.put的參數(shù)呢?直接返回相應(yīng)的value,也就是null,這時候null==null是true。竟然返回了true。很明顯就是錯誤的返回結(jié)果呀。
這其實(shí)也是去重復(fù)的原理。對于刪除方法其實(shí)也是一樣的。
2、構(gòu)造函數(shù)
HashSet提供的構(gòu)造方法很多,有5個,在這里我想說明的是每一種構(gòu)造方法,其實(shí)都是創(chuàng)建的HashMap。這也證明了我們文章開頭提到的內(nèi)部基于HashMap。
3、其他方法
增刪方法我們已經(jīng)提到了,在這里我們主要看一下其他方法。
上面的方法還包含了遍歷元素的方式。
HashSet就是這么簡單,源碼里面幾乎所有的方法都是HashMap實(shí)現(xiàn)的。
總結(jié)
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot使用Flyway進(jìn)行數(shù)據(jù)庫管理的操作方法
Flyway是一個開源的數(shù)據(jù)庫版本管理工具,并且極力主張“約定大于配置”,簡單、專注、強(qiáng)大。接下來通過本文給大家介紹SpringBoot使用Flyway進(jìn)行數(shù)據(jù)庫管理的方法,感興趣的朋友一起看看吧2021-09-09SpringBoot工程Docker多環(huán)境中使用同一個Jar包解決方案
在Docker多環(huán)境部署中,SpringBoot工程可以通過環(huán)境變量來動態(tài)改變配置,無需重新打包,利用volume掛載或docker?cp命令,可以將配置文件直接傳入容器,提高部署效率,并保證安全性2024-09-09java8中NIO緩沖區(qū)(Buffer)的數(shù)據(jù)存儲詳解
在本篇文章中小編給大家分享了關(guān)于java8中NIO緩沖區(qū)(Buffer)的數(shù)據(jù)存儲的相關(guān)知識點(diǎn),需要的朋友們參考下。2019-04-04Java實(shí)現(xiàn)對華北、華南、華東和華中四個區(qū)域的劃分
在Java中,通過定義枚舉類、編寫主程序和進(jìn)行測試,本文詳細(xì)介紹了如何劃分華北、華南、華東和華中四個區(qū)域,首先定義枚舉類標(biāo)識區(qū)域,然后通過主程序接收用戶輸入并返回相應(yīng)區(qū)域,最后通過測試用例確保正確性,文章還介紹了甘特圖和餅狀圖的使用2024-09-09一文帶你掌握springBoot如何做到優(yōu)雅停機(jī)的
在分布式系統(tǒng)中,服務(wù)的優(yōu)雅停機(jī)(Graceful Shutdown)是確保業(yè)務(wù)連續(xù)性的重要機(jī)制,下面就跟隨小編一起來深入了解下springBoot實(shí)現(xiàn)優(yōu)雅停機(jī)的具體方式吧2025-04-04