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; } ... }