Java Set 經常使用集合 HashSet、LinkedHashSet、TreeSet


Java 中的 Set 是很是經常使用的數據類型。Set 是無序的 Collection,Java Set 有三個經常使用的實現類,分別是:HashSet、LinkedHashSet、TreeSetjava



本文基於 JDK8 分析安全


HashSet

HashSet 繼承自 AbstractSet,實現了 Set 接口。底層基於 HashMap 實現,是一個不容許有重複元素的無序集合。容許 null 元素,非線程安全。HashSet 還實現了 Cloneable、Serializable 接口,因此 HashSet 是支持複製、序列化的函數

因此說,HashMap 是替 HashSet 打工的。就像老闆手下的員工,不辭辛苦,作牛作馬,像極了被剝削的咱們(小聲嗶嗶)this

// 用於存儲元素的 HashMap
private transient HashMap<E,Object> map;
// 湊數的值元素,
private static final Object PRESENT = new Object();

HashSet 有五個構造函數,解釋下第二個構造函數:默認加載因子爲 0.75 的狀況下,假設 c 的元素個數就是 map 此時的最大閾值,最大閾值爲 (int) (c.size()/.75f),再加一,經過 HashMap 的擴容機制(取大於當前容量的最小二次冪),就能夠取得最適合的容量大小線程

// 構造一個默認容量爲 16 的 HashMap
public HashSet()  {
    map = new HashMap<>();
}
// 將 Collection 中的元素賦給 HashMap
public HashSet(Collection<? extends E> c) {
    map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
    addAll(c);
}
// 指定 HashMap 的初始容量和加載因子
public HashSet(int initialCapacity, float loadFactor) {
    map = new HashMap<>(initialCapacity, loadFactor);
}
// 指定 HashMap 的初始容量
public HashSet(int initialCapacity) {
    map = new HashMap<>(initialCapacity);
}
// 供 LinkedHashSet 使用
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
    map = new LinkedHashMap<>(initialCapacity, loadFactor);
}

HashSet 經常使用方法

第一個是 add 方法。HashSet 使用 HashMap 保證元素不重複,熟悉 HashMap 的都知道,HashMap 的 Key 是不容許重複的,因此能夠把要添加的元素做爲 HashMap 的 Key 保存,但 Value 仍是要有的,因此 HashSet 又定義了一個靜態常量對象 PRESENT 來湊數,實際上並無什麼意義code

private static final Object PRESENT = new Object();

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

到這裏就一目瞭然了,HashSet 中添加元素的方法其實就是調用 HashMap 的 put 方法,若是 put 方法的返回值爲 null,證實以 e 爲鍵的元素不存在,則能夠添加;不然會把原有的值刪除並覆蓋,並返回原來的值。因此當 add 方法中的條件判斷成立,則證實添加成功,反之則失敗。若是不瞭解 HashMap 的機制,能夠看一下下面這張圖對象

![](G:\SSS\Java\Java SE\博客\HashMap add.png)blog

至於其餘的 remove、contains 就更不用說了,全是 HashMap 的知識,再也不贅述排序


LinkedHashSet

LinkedHashSet 是 HashSet 的子類,實現了 Set 接口,Set 有的特色它都有。既然 HashSet 靠 HashMap 幹活,那是否 LinkedHashSet 也有本身的小弟呢?(沒錯,說的就是你 LinkedHashMap)繼承

還記得以前提到在 HashSet 有一個專供 LinkedHashSet 使用的構造方法嗎?這個構造方法只能由 LinkedHashSet 調用,參數 dummy 並無實際意義,只是爲了和 HashSet 中其餘參數區分開罷了(重載原理)

LinkedHashMap 基於雙向鏈表實現,相比於 HashMap 最大的不一樣就是有序。LinkedHashSet 中除了四個構造器之外再無其餘方法,所有繼承自 HashSet。若是想了解更多,就去看看 LinkedHashMap 吧

// HashSet 中專供 LinkedHashSet 使用的構造方法
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
    map = new LinkedHashMap<>(initialCapacity, loadFactor);
}

// LinkedHashSet 的構造方法
public LinkedHashSet(int initialCapacity, float loadFactor) {
    super(initialCapacity, loadFactor, true);
}

public LinkedHashSet(int initialCapacity) {
    super(initialCapacity, .75f, true);
}

public LinkedHashSet() {
    super(16, .75f, true);
}

public LinkedHashSet(Collection<? extends E> c) {
    super(Math.max(2*c.size(), 11), .75f, true);
    addAll(c);
}

TreeSet

在此以前先了解一下 SortedSet,SortSet 擴展了 Set 並提供其元素的總排序,要求全部元素都必須實現 Comparable 接口,並且全部元素都必須是可比較的,即兩個對象能夠互相做爲 compareTo 方法的參數。從這裏能夠看出,SortedSet 所謂的有序並非咱們一般認爲的前後插入順序,而是根據對象的比較函數對元素排序。SortSet 接口的方法以下:

// 返回用於對此集合中的元素進行排序的比較器,若是此集合使用其元素的天然順序,則返回 null
Comparator<? super E> comparator();
// 返回此集合的部分元素,元素範圍從 fromElement(包括)到 toElement(不包括)
SortedSet<E> subSet(E fromElement, E toElement);
// 返回此集合的部元素,其中元素所有小於 toElement
SortedSet<E> headSet(E toElement);
// 返回此集合的部分元素,其中元素所有大於或等於 fromElement
SortedSet<E> tailSet(E fromElement);
// 返回此集合中當前的第一個(最低)元素
E first();
// 返回此集合中當前的最後一個(最高)元素
E last();

NavigableSet 實現了 Sorted 接口,其自己也是一個接口,對 SortedHash 進行了擴展,支持導航方法,例如查找與指定目標最匹配項等。TreeSet 繼承自 AbstractSet,實現了 NavigableSet 接口。TreeSet 基於 TreeMap 實現,其構造方法以下:

private transient NavigableMap<E,Object> m;

// 構造一個指定的 NavigableMap 的集合
TreeSet(NavigableMap<E,Object> m) {
    this.m = m;
}
// 默認方法,根據元素的天然排序進行排序
public TreeSet() {
    this(new TreeMap<E,Object>());
}
// 指定比較器進行排序
public TreeSet(Comparator<? super E> comparator) {
    this(new TreeMap<>(comparator));
}
// 構造一個包含指定集合中元素的集合,根據元素的天然排序進行排序
public TreeSet(Collection<? extends E> c) {
    this();
    addAll(c);
}
// 構造一個包含相同元素的集合,並使用與指定排序集相同的排序
public TreeSet(SortedSet<E> s) {
    this(s.comparator());
    addAll(s);
}

TreeSet 也是基於 TreeMap 工做的,TreeMap 也是一個可排序的 Map,排序原理也是依靠比較器,更多的細節請了解 TreeMap

相關文章
相關標籤/搜索