【源碼閱讀】HashSet 和 LinkedHashSet 1.8

HashSet、LinkedHashSet 兩個類是在 HashMap / LinkedHashMap 的基礎上組裝起來的類,因此本文側重:java

  • 爲何要組合 HashMap / LinkedHashMap?
  • 如何組合 HashMap / LinkedHashMap?

1、什麼是 HashSet ?

  • 線程不安全
  • 底層實現基於 HashMap
  • 迭代過程當中,若是數據被修改,會產生快速失敗。

1. 成員變量

public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable {
    ...
    // 鍵值Map
    private transient HashMap<E,Object> map;
    // 用做全部鍵對應的值,鍵所對應的值都相等
    private static final Object PRESENT = new Object();
    ...
}

Q1:爲何要組合 HashMap 而不繼承 HashMap?安全

  • 繼承表示父子類是同一類事物,而 Set 和 Map 原本就是想表達兩類事物,因此用繼承欠妥,並且 java 只支持單繼承,可擴展性不強。
  • 組合更加靈活,能夠任意的組合現有的基礎類,而且能夠在基礎類方法的基礎上進行擴展。

2. 構造方法

// 調用的是HashMap的構造方法
public HashSet() {
    map = new HashMap<>();
}
public HashSet(int initialCapacity, float loadFactor) {
    map = new HashMap<>(initialCapacity, loadFactor);
}

public HashSet(int initialCapacity) {
    map = new HashMap<>(initialCapacity);
}

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

Math.max ((int) (c.size ()/.75f) + 1, 16),對 HashMap 的容量進行了計算:線程

  • HashMap 的閾值計算:Map 的容量 * 0.75f
  • 若是給定 HashMap 初始容量小於 16 ,就按照 HashMap 默 認的 16 初始化

Q:往 HashMap 裏拷貝大集合時,如何給 HashMap 初始化大小?code

  • A:借鑑上述初始化思路:max(指望值 / 0.75 + 1,默認值 16)

2、什麼是 LinkedHashSet?

  • LinkedHashSet 是具備可預知迭代順序的 Set 接口的哈希表和連接列表實現。
  • LinkedHashSet 內部維護着一條雙向列表,此連接列表定義了迭代順序,可爲插入順序或是訪問順序。
  • LinkedHashSet 裏面有一個 LinkedHashMap (適配器模式),對 LinkedHashSet 的方法調用都會轉換成合適的 LinkedHashMap 方法。
public class LinkedHashSet<E> extends HashSet<E> implements Set<E>, Cloneable, java.io.Serializable {
    ...
    public LinkedHashSet(int initialCapacity, float loadFactor) {
        map = new LinkedHashMap<>(initialCapacity, loadFactor);
    }
    ...
    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }
    ...
}
相關文章
相關標籤/搜索