0 前言
HashSet 是一個沒有重複元素的集合.主要由 HashMap 實作,不保證元素順序,而允許 null 元素.非線程安全,如果需要安全請自行加鎖,或者使用 Collections.synchronizedSet包裝.最好在建立時完成這一操作,以防止對該 set 進行意外的不同步通路.
1 繼承體系
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5SYihzN3AjZmNDOlNmM3ATO4UmY0IjN1E2N0QmNxMzY38CX5d2bs92Yl1iclB3bsVmdlR2LcNWaw9CXt92Yu4GZjlGbh5yYjV3Lc9CX6MHc0RHaiojIsJye.png)
HashSet繼承自AbstractSet,并且實作了Set接口.HashSet的本質是一個"沒有重複元素"的集合,它是通過HashMap實作的。HashSet中含有一個"HashMap類型的成員變量"map,HashSet的操作函數,實際上都是通過map實作的.
2 屬性
- HashSet 組合了 HashMap,把 HashMap 當作自己的一個局部變量
-
和阿裡面試官對線,多虧看完這篇HashSet源碼解析0 前言1 繼承體系2 屬性3 構造方法4 add(E e)5 remove6 總結 - 可以在基礎類方法的基礎上進行擴充,而且方法命名可以任意命名,無需和基礎類的方法名稱保持一緻.
- 與後備Map中的對象關聯的虛拟 value
-
和阿裡面試官對線,多虧看完這篇HashSet源碼解析0 前言1 繼承體系2 屬性3 構造方法4 add(E e)5 remove6 總結
3 構造方法
3.1 無參
- 直接 new HashMap
-
和阿裡面試官對線,多虧看完這篇HashSet源碼解析0 前言1 繼承體系2 屬性3 構造方法4 add(E e)5 remove6 總結
3.2 有參
- 當有原始集合資料進行初始化的情況下
-
和阿裡面試官對線,多虧看完這篇HashSet源碼解析0 前言1 繼承體系2 屬性3 構造方法4 add(E e)5 remove6 總結 - 計算 HashMap 的容量:取括号中兩個數的最大值
(期望值 / 0.75+1,預設值 16)
若給定 HashMap 初始容量
< 16
按照 HashMap 預設的 16 初始化
> 16
按給定值初始化
HashMap 擴容門檻值:Map容量 * 0.75f,而此處的計算值正好比閥值大1,就不會立即擴容.
HashSet 的 API 都比較簡單,就是對 HashMap 的進行了簡單的包裝.我們簡單看幾個,
4 add(E e)
- 直接使用 HashMap 的 put 方法并判斷
-
和阿裡面試官對線,多虧看完這篇HashSet源碼解析0 前言1 繼承體系2 屬性3 構造方法4 add(E e)5 remove6 總結 - 如果指定的元素尚不存在,則将其添加到該 set 中.更确切地說
- 如果此元素集中不包含任何元素e2,使得
則将指定元素e添加到該元素集合中(e==null ? e2==null : e.equals(e2))
- 如果此集合已包含該元素,則調用将使該集合保持不變并傳回false
5 remove
- 直接調用 HashMap 的 remove 方法并判斷
-
和阿裡面試官對線,多虧看完這篇HashSet源碼解析0 前言1 繼承體系2 屬性3 構造方法4 add(E e)5 remove6 總結 - 如果存在,則從此set中删除指定的元素.更确切地講,如果此set包含這樣的元素
(o==null ? e==null : o.equals(e))
則删除元素.
如果此集合包含該元素(或者說,如果此集合由于方法的調用而被更改),則傳回true.(一旦調用傳回,此集合将不包含該元素)
其他方法實作類似如此,不再贅述.
6 總結
HashSet 的實作給我們留下了一些最佳實踐
- 組合有時比繼承更加适用
- 注意封裝複雜邏輯,使對外接口充滿使用者體驗
- 要對組合的其他資料結構十分了解,才能使代碼設計達到 1+1>2 奇效.