鍍金池/ 教程/ Java/ LinkedHashSet 的實現(xiàn)原理
LinkedHashSet 的實現(xiàn)原理
LinkedHashMap 與 LRUcache
HashSet 和 HashMap 的比較
Hashtable 的實現(xiàn)原理
ArrayList 的實現(xiàn)原理
HashSet 的實現(xiàn)原理
HashMap 的實現(xiàn)原理
LinkedList 的實現(xiàn)原理
ConcurrentHashMap 的實現(xiàn)原理
LinkedHashMap 的實現(xiàn)原理

LinkedHashSet 的實現(xiàn)原理

LinkedHashSet 概述

思考了好久,到底要不要總結(jié) LinkedHashSet 的內(nèi)容 = = 我在之前的博文中,分別寫了 HashMap 和 HashSet,然后我們可以看到 HashSet 的方法基本上都是基于 HashMap 來實現(xiàn)的,說白了,HashSet內(nèi)部的數(shù)據(jù)結(jié)構(gòu)就是一個 HashMap,其方法的內(nèi)部幾乎就是在調(diào)用 HashMap 的方法。

LinkedHashSet 首先我們需要知道的是它是一個 Set 的實現(xiàn),所以它其中存的肯定不是鍵值對,而是值。此實現(xiàn)與 HashSet 的不同之處在于,LinkedHashSet 維護(hù)著一個運(yùn)行于所有條目的雙重鏈接列表。此鏈接列表定義了迭代順序,該迭代順序可為插入順序或是訪問順序。

看到上面的介紹,是不是感覺其與 HashMap 和 LinkedHashMap 的關(guān)系很像?

注意,此實現(xiàn)不是同步的。如果多個線程同時訪問鏈接的哈希Set,而其中至少一個線程修改了該 Set,則它必須保持外部同步。

小 Demo

LinkedHashMap的實現(xiàn)原理中,通過例子演示了 HashMap 和 LinkedHashMap 的區(qū)別。舉一反三,我們現(xiàn)在學(xué)習(xí)的LinkedHashSet與之前的很相同,只不過之前存的是鍵值對,而現(xiàn)在存的只有值。

所以我就不再具體的貼代碼在這邊了,但我們可以肯定的是,LinkedHashSet 是可以按照插入順序或者訪問順序進(jìn)行迭代。

LinkedHashSet 的實現(xiàn)

對于 LinkedHashSet 而言,它繼承與 HashSet、又基于 LinkedHashMap 來實現(xiàn)的。

LinkedHashSet 底層使用 LinkedHashMap 來保存所有元素,它繼承與 HashSet,其所有的方法操作上又與 HashSet 相同,因此 LinkedHashSet 的實現(xiàn)上非常簡單,只提供了四個構(gòu)造方法,并通過傳遞一個標(biāo)識參數(shù),調(diào)用父類的構(gòu)造器,底層構(gòu)造一個 LinkedHashMap 來實現(xiàn),在相關(guān)操作上與父類 HashSet 的操作相同,直接調(diào)用父類 HashSet 的方法即可。LinkedHashSet 的源代碼如下:

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

    private static final long serialVersionUID = -2851667679971038690L;

    /**
     * 構(gòu)造一個帶有指定初始容量和加載因子的新空鏈接哈希set。
     *
     * 底層會調(diào)用父類的構(gòu)造方法,構(gòu)造一個有指定初始容量和加載因子的LinkedHashMap實例。
     * @param initialCapacity 初始容量。
     * @param loadFactor 加載因子。
     */
    public LinkedHashSet(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor, true);
    }

    /**
     * 構(gòu)造一個帶指定初始容量和默認(rèn)加載因子0.75的新空鏈接哈希set。
     *
     * 底層會調(diào)用父類的構(gòu)造方法,構(gòu)造一個帶指定初始容量和默認(rèn)加載因子0.75的LinkedHashMap實例。
     * @param initialCapacity 初始容量。
     */
    public LinkedHashSet(int initialCapacity) {
        super(initialCapacity, .75f, true);
    }

    /**
     * 構(gòu)造一個帶默認(rèn)初始容量16和加載因子0.75的新空鏈接哈希set。
     *
     * 底層會調(diào)用父類的構(gòu)造方法,構(gòu)造一個帶默認(rèn)初始容量16和加載因子0.75的LinkedHashMap實例。
     */
    public LinkedHashSet() {
        super(16, .75f, true);
    }

    /**
     * 構(gòu)造一個與指定collection中的元素相同的新鏈接哈希set。
     *
     * 底層會調(diào)用父類的構(gòu)造方法,構(gòu)造一個足以包含指定collection
     * 中所有元素的初始容量和加載因子為0.75的LinkedHashMap實例。
     * @param c 其中的元素將存放在此set中的collection。
     */
    public LinkedHashSet(Collection<? extends E> c) {
        super(Math.max(2*c.size(), 11), .75f, true);
        addAll(c);
    }
}

以上幾乎就是 LinkedHashSet 的全部代碼了,那么讀者可能就會懷疑了,不是說 LinkedHashSet 是基于 LinkedHashMap 實現(xiàn)的嗎?那我為什么在源碼中甚至都沒有看到出現(xiàn)過 LinkedHashMap。不要著急,我們可以看到在 LinkedHashSet 的構(gòu)造方法中,其調(diào)用了父類的構(gòu)造方法。我們可以進(jìn)去看一下:

/**
     * 以指定的initialCapacity和loadFactor構(gòu)造一個新的空鏈接哈希集合。
     * 此構(gòu)造函數(shù)為包訪問權(quán)限,不對外公開,實際只是是對LinkedHashSet的支持。
     *
     * 實際底層會以指定的參數(shù)構(gòu)造一個空LinkedHashMap實例來實現(xiàn)。
     * @param initialCapacity 初始容量。
     * @param loadFactor 加載因子。
     * @param dummy 標(biāo)記。
     */
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
    map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);
}

在父類 HashSet 中,專為 LinkedHashSet 提供的構(gòu)造方法如下,該方法為包訪問權(quán)限,并未對外公開。

由上述源代碼可見,LinkedHashSet 通過繼承 HashSet,底層使用 LinkedHashMap,以很簡單明了的方式來實現(xiàn)了其自身的所有功能。

總結(jié)

以上就是關(guān)于 LinkedHashSet 的內(nèi)容,我們只是從概述上以及構(gòu)造方法這幾個方面介紹了,并不是我們不想去深入其讀取或者寫入方法,而是其本身沒有實現(xiàn),只是繼承于父類 HashSet 的方法。

所以我們需要注意的點是:

  • LinkedHashSet 是 Set 的一個具體實現(xiàn),其維護(hù)著一個運(yùn)行于所有條目的雙重鏈接列表。此鏈接列表定義了迭代順序,該迭代順序可為插入順序或是訪問順序。
  • LinkedHashSet 繼承與 HashSet,并且其內(nèi)部是通過 LinkedHashMap 來實現(xiàn)的。有點類似于我們之前說的LinkedHashMap 其內(nèi)部是基于 Hashmap 實現(xiàn)一樣,不過還是有一點點區(qū)別的(具體的區(qū)別大家可以自己去思考一下)。
  • 如果我們需要迭代的順序為插入順序或者訪問順序,那么 LinkedHashSet 是需要你首先考慮的。