LinkedHashSet 的實現原理


LinkedHashSet 概述

思考了好久,到底要不要總結 LinkedHashSet 的內容 = = 我在之前的博文中,分別寫了 HashMap 和 HashSet,然后我們可以看到 HashSet 的方法基本上都是基於 HashMap 來實現的,說白了,HashSet內部的數據結構就是一個 HashMap,其方法的內部幾乎就是在調用 HashMap 的方法。

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

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

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

小 Demo

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

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

LinkedHashSet 的實現

對於 LinkedHashSet 而言,它繼承與 HashSet、又基於 LinkedHashMap 來實現的。

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

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

    private static final long serialVersionUID = -2851667679971038690L;

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

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

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

    /**
     * 構造一個與指定collection中的元素相同的新鏈接哈希set。
     *
     * 底層會調用父類的構造方法,構造一個足以包含指定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 實現的嗎?那我為什么在源碼中甚至都沒有看到出現過 LinkedHashMap。不要着急,我們可以看到在 LinkedHashSet 的構造方法中,其調用了父類的構造方法。我們可以進去看一下:

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

在父類 HashSet 中,專為 LinkedHashSet 提供的構造方法如下,該方法為包訪問權限,並未對外公開。

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

總結

以上就是關於 LinkedHashSet 的內容,我們只是從概述上以及構造方法這幾個方面介紹了,並不是我們不想去深入其讀取或者寫入方法,而是其本身沒有實現,只是繼承於父類 HashSet 的方法。

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

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM