前言
HashSet
實現了Set
介面,它的底層是由HashMap
來支援的。HashSet
的元素實際上是儲存在底層HashMap
的key
上的。由於HashMap
的無序不重複特性,HashSet
儲存的元素也是無序的,並且元素也不能重複,同時也只允許儲存一個null
元素。
HashSet原始碼分析
主要屬性:
// HashSet底層map
private transient HashMap<E,Object> map;
// 虛擬物件
private static final Object PRESENT = new Object();複製程式碼
HashSet
是通過HashMap
來儲存元素,由於只需要在key
中儲存,所以採用虛擬物件PRESENT
對應map
中插入key-value
的value
值的引用。每次向map
中新增元素時,鍵值對對應的value
都是PRESENT
。
建構函式:
// 預設無參構造
public HashSet() {
map = new HashMap<>();
}
// 根據已有集合元素來構造HashSet
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
// 給定初始容量
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
// 給定初始容量和載入因子
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
// 這個建構函式外部不能呼叫,供LinkedHashSet複寫
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}複製程式碼
建構函式都是初始map
,以便加入元素的時候儲存。
重要方法:
// 集合大小
public int size() {
return map.size();
}
// 集合是否為空
public boolean isEmpty() {
return map.isEmpty();
}
// 新增元素
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
// 移除元素
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
// 清空集合
public void clear() {
map.clear();
}
// 集合中是否有元素o
public boolean contains(Object o) {
return map.containsKey(o);
}複製程式碼
HashSet
的增刪改查,同時直接操作map
來完成的,程式碼都非常簡單。
LinkedHashSet
LinkedHashSet
繼承自HashSet
,它的構造方法:
public LinkedHashSet() {
super(16, .75f, true);
}
public LinkedHashSet(int initialCapacity) {
super(initialCapacity, .75f, true);
}
public LinkedHashSet(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor, true);
}
public LinkedHashSet(Collection<? extends E> c) {
super(Math.max(2*c.size(), 11), .75f, true);
addAll(c);
}複製程式碼
LinkedHashSet
構造方法呼叫了父類HashSet
的這個構造方法:
// LinkedHashSet複寫,初始化LinkedHashMap
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}複製程式碼
所以,它的底層是一個LinkedHashMap
,元素的所有操作都是由LinkedHashMap
來維護。LinkedHashSet
與HashSet
的區別和LinkedHashMap
與HashMap
的區別一樣,LinkedHashMap
和LinkedHashSet
是有序的,內部由雙向連結串列來記錄順序,而HashMap
和HashSet
都是無序的。
最後
對於HashSet/LinkedHashSet
,只要閱讀過HashMap/LinkedHashMap
的原始碼,基本上就能完全瞭解它的實現原理。HashSet/LinkedHashSet
中資料的存入、刪除、訪問都是都是直接操作內部的HashMap
,可以說HashSet/LinkedHashSet
是在HashMap/LinkedHashMap
的基礎上加了一層殼。他們唯一的區別就是HashSet/LinkedHashSet
儲存的元素時單個的資料或物件,而HashMap/LinkedHashMap
儲存的元素時鍵值對。