HashSet源碼解析

通過之前對其他的集合的再讀及整理,HashSet 相對來說就比較簡單了,直接上源碼看下構造函數:

public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable {
    static final long serialVersionUID = -5024744406713321676L;

    private transient HashMap<E,Object> map;

    // 虛擬對象
    private static final Object PRESENT = new Object();

    // 無參構造
    public HashSet() {
        map = new HashMap<>();
    }

    // 集合構造
    public HashSet(Collection<? extends E> c) {
        map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
        addAll(c);
    }

    // 初始化容量及負載因子構造
    public HashSet(int initialCapacity, float loadFactor) {
        map = new HashMap<>(initialCapacity, loadFactor);
    }

    // 初始化容量構造
    public HashSet(int initialCapacity) {
        map = new HashMap<>(initialCapacity);
    }

    // 由於默認修飾符,同包可訪問,我們用不到,在LinkedLinkedHashMap中有具體應用,後期會講解
    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
        map = new LinkedHashMap<>(initialCapacity, loadFactor);
    }
}

可以很容易看出來,HashSet 底層其實就是維護了一個 HashMap,所以 默認長度爲 16,負載因子爲 0.75f,樹化閥值爲8,反樹化閥值爲6,等等全是HashMap的特性。那麼他是怎麼實現無序 不可重複的特性的呢? 重點還在於虛擬對象 PRESENT ,我們從add 方法中可以確定:

    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

在添加新的元素時,以新的元素作爲key , 虛擬對象 作爲 value 。因爲每次添加同一個虛擬對象,所以 只有保持 key的不同才能保證唯一,由此實現了 不可重複的特性。而HashMap 本身是通過 key的hash值來確定存放的位置,自然就是無序。

在刪除的方法中也是同樣的邏輯,找到對應的key 直接把該位置元素刪除,如果是鏈表或者是樹,道理相通,具體可以參考HashMap

    public boolean remove(Object o) {
        return map.remove(o)==PRESENT;
    }

HashSet 相對較爲簡單,其他的方法也是一樣,此時就不一一解析了。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章