集合系列 Set:HashSet

HashSet 是 Set 集合的哈希實現,其繼承了 AbstractSet 抽象類,並實現了 Set 接口。

public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable

原理

爲了深入理解 HashSet 的原理,我們將從類成員變量、構造方法、核心方法兩個方面逐一介紹。

類成員變量

// HashSet內部使用HashMap存儲
private transient HashMap<E,Object> map;
// 存儲在value上的值
private static final Object PRESENT = new Object();

從類成員變量我們可以知道,HashSet 內部使用 HashMap 存儲,而 PRESENT 則是存儲在所有 key 上的 value。因此對於 HashSet 來說,其所有 key 的 value 都相同。

構造方法

HashSet 一共有 5 個構造方法。

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);
}
    
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
    map = new LinkedHashMap<>(initialCapacity, loadFactor);
}

可以看到構造方法傳入的參數其實就是用於初始化 HashMap 對象,主要有:initialCapacity(初始大小)、loadFactor(擴容因子)。這幾個構造參數內容並不複雜,這裏就不細講了。

這裏有一個關鍵的細節,即第 5 個方法使用 LinkedHashMap 實現的,而不是用 HashMap 實現的。而我們後面要講到的 LinkedHashSet 其實就是使用 LinkedHashMap 實現的,其保存了插入元素的順序。

核心方法

對於 HashSet 來說,其核心的方法有:add、remove。

我們先看 add 方法。

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

可以看到 add 方法直接調用了 HashMap 對象的 put 方法。如果 Set 集合插入成功,那麼就返回 true,否則返回 false。

接着我們看看 remove 方法。

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

可以看到 remove 方法直接調用了 HashMap 對象的 remove 方法。如果刪除成功,就返回 true,否則返回 false。

總結

HashSet 的源碼也是非常簡單了,其直接借用了 HashMap 的實現。所以如果你弄懂了 HashMap,那麼 HashSet 自然不在話下了。

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