探索HashSet底層實現
阿新 • • 發佈:2020-12-22
前言
HashSet的底層實現依賴於HashMap,所以它的資料結構也是陣列 + 連結串列 + 紅黑樹
,而對於它的類註釋也沒什麼好總結的,探索HashSet底層實現是基於JDK1.8
。仔細一想,HashSet存在的意義是什麼?有時候需要新增元素時,也就是隻有單個物件,並沒有所謂的鍵值對,或許還有些用處,可這ArrayList也能做到啊!可是相比之下,HashSet由於有HashMap撐腰,它的效能要高於ArrayList,所以我認為HashSet是List和Map獨有的特性結合後的產物。
資料結構
//可序列化、可克隆 public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable { //直接使用了HashMap來儲存它的元素 private transient HashMap<E,Object> map; //既然用了HashMap就要考慮值應該存什麼,就是它了,不管新增的元素是什麼,它都作為值 private static final Object PRESENT = new Object(); }
建構函式
/** * 初始化 */ public HashSet() { map = new HashMap<>(); } /** * 指定集合來初始化 * @param c 指定集合 */ public HashSet(Collection<? extends E> c) { map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16)); addAll(c); } /** * 指定初始容量與載入因子來初始化 * @param initialCapacity 指定初始容量 * @param loadFactor 指定載入因子 */ public HashSet(int initialCapacity, float loadFactor) { map = new HashMap<>(initialCapacity, loadFactor); } /** * 指定初始容量來初始化 * @param initialCapacity 指定初始容量 */ public HashSet(int initialCapacity) { map = new HashMap<>(initialCapacity); } /** * 指定初始容量與載入因子來初始化 * 對比上面這裡構造了LinkedHashMap,說明它是有序的 * @param initialCapacity 指定初始容量 * @param loadFactor 指定載入因子 * @param dummy 無實際意義,為了與上面的建構函式區分開來 */ HashSet(int initialCapacity, float loadFactor, boolean dummy) { map = new LinkedHashMap<>(initialCapacity, loadFactor); }
簡單方法
/** * 獲取迭代器 * @return 迭代器 */ public Iterator<E> iterator() { return map.keySet().iterator(); } /** * 獲取元素個數 * @return 元素個數 */ public int size() { return map.size(); } /** * HashSet是否為空 * @return 是否為空 */ public boolean isEmpty() { return map.isEmpty(); } /** * HashSet是否包含指定元素 * @param o 指定元素 * @return 是否包含指定元素 */ public boolean contains(Object o) { return map.containsKey(o); } /** * 新增元素 * @param e 指定元素 * @return 是否新增成功 */ public boolean add(E e) { return map.put(e, PRESENT)==null; } /** * 移除指定元素 * @param o 指定元素 * @return 是否移除成功 */ public boolean remove(Object o) { return map.remove(o)==PRESENT; } /** * 清空 */ public void clear() { map.clear(); } /** * 淺克隆 */ public Object clone() { try { HashSet<E> newSet = (HashSet<E>) super.clone(); newSet.map = (HashMap<E, Object>) map.clone(); return newSet; } catch (CloneNotSupportedException e) { throw new InternalError(e); } }
總結
-
HashSet無序、不可重複、非執行緒安全。
-
HashSet允許存放空元素。
-
HashSet底層基於HashMap。
-
兩個相等的物件,即hashCode與equals都相等的情況,HashMap底層只是進行值替換,並未理睬鍵,所以就呈現了在往HashSet新增相等的物件時,只添加了第一個物件,第二個物件並未新增。
重點關注
基於HashMap