淺析Java集合中的LinkedHashSet
1. 類的特性
LinkedHashSet的類注釋,提供了以下信息
- LinkedHashSet基于哈希表和鏈表實現(xiàn)了Set接口
- 允許有且只有一個null值
- 在所有的元素中維護了一個雙向鏈表,可以維護元素的插入順序
性能:
- 與HashSet一樣,在散列均勻的情況下,基本操作(add、remove、contains)的時間復雜度為O ( 1 ) O(1)O(1)
- 但實際性能稍遜于HashSet,因為維護元素間的雙向鏈表需要一定的開銷。
- LinkedHashSet元素的遍歷,不再基于桶,而是基于鏈表,遍歷時間與元素個數(shù)成正比
- LinkedHashSet是非線程安全的,多線程訪問,可以使用Collections.synchronizedSet()將其轉為線程安全的set類型
- 使用fail-fast 迭代器,一旦創(chuàng)建好迭代器,除非使用迭代器自身的remove方法,其他任何修改結構的方法,都將觸發(fā)迭代器拋出ConcurrentModificationException 異常
總結:
- 使用哈希表加(雙向)鏈表的結構,允許null值,可以維護元素的插入順序
- 基本操作的性能為O ( 1 ) O(1)O(1),遍歷是基于鏈表而非桶
- 非線程安全,使用fail-fast 迭代器
疑問:
- 回想其余set類實現(xiàn),LinkedHashSet應該是基于LinkedHashMap實現(xiàn)的。
- 為何類注釋中,沒有說LinkedHashSet支持訪問順序呢?
- 只是說,通過雙向鏈表維護了元素的插入順序
2. LinkedHashSet & LinkedHashMap
2.1 LinkedHashSet的實現(xiàn)如此簡單
查看LinkedHashSet源碼,其結構如下

除了構造函數(shù),沒有常見的set類的關鍵方法,甚至沒有成員變量
讓人感覺很神奇,為何實現(xiàn)如此簡單?
2.2 類圖
LinkedHashSet類的定義如下
public class LinkedHashSet<E> extends HashSet<E>
implements Set<E>, Cloneable, java.io.Serializable 類圖如下

查看LinkedHashMap的類圖,二者非常相似,簡直是照葫蘆畫瓢
2.3 關聯(lián)分析
- LinkedHashMap基于HashMap實現(xiàn),對一些關鍵方法進行了重寫,從而在所有的entry中維護一個雙向鏈表
- HashSet基于HashMap實現(xiàn),存在一個default構造函數(shù),使用子類LinkedHashMap初始化HashMap
- dummy入?yún)ⅲ簾o意義的參數(shù),只是為了實現(xiàn)重載,與其他的構造函數(shù)相區(qū)別
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}- 從Java的多態(tài)可知,通過該構造函數(shù)初始化的 map 字段,實際執(zhí)行時將調用子類LinkedHashMap的相關方法
巧妙之處來了:
LinkedHashSet的構造函數(shù),實際都調用HashSet的上述 default 構造函數(shù)
也就是說,LinkedHashSet中的 map 字段,實際為LinkedHashMap類型
這樣,所有entry之間就存在一個雙向鏈表,即LinkedHashSet的所有元素之間存在一個雙向鏈表
從而,LinkedHashSet中元素是有序的,為元素的插入順序
// 指定初始化容量和loadFactor的空set
public LinkedHashSet(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor, true);
}
// 指定初始化容量、使用默認loadFactor的空set
public LinkedHashSet(int initialCapacity) {
super(initialCapacity, .75f, true);
}
// 使用默認值構建一個空set
public LinkedHashSet() {
super(16, .75f, true);
}
// 基于指定的元素構建一個set
public LinkedHashSet(Collection<? extends E> c) {
super(Math.max(2*c.size(), 11), .75f, true);
addAll(c);
}2.4 為何不支持訪問順序?
從HashSet的 default 構造函數(shù)可以看出,構建的LinkedHashMap將默認使用插入順序
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}因此,基于LinkedHashMap的LinkedHashSet,也將使用插入順序
沒有其他的構造函數(shù)可以提供一個具有訪問順序的LinkedHashMap,LinkedHashSet自然也不會支持訪問順序
3. 總結
關于LinkedHashSet
- 繼承HashSet類,巧妙的依靠Java的繼承與多態(tài),建立起與LinkedHashMap之間的聯(lián)系
- 實際上,基于LinkedHashMap實現(xiàn)了Set接口
與HashSet的區(qū)別
- 最大的區(qū)別:元素是有序的,支持插入順序
- 先學習List類:ArrayList、Vector、LinkedList
- 再學習Map類:TreeMap(先學習紅黑樹)、HashMap、LinkedHashMap
- 最后學習Set類:TreeSet、HashSet、LinkedHashSet;與上述Map類一起,對照學習
到此這篇關于淺析Java集合中的LinkedHashSet的文章就介紹到這了,更多相關Java的LinkedHashSet內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
List調用toString()方法后,去除兩頭的中括號實例
下面小編就為大家?guī)硪黄狶ist調用toString()方法后,去除兩頭的中括號實例。希望對大家有所幫助。一起跟隨小編過來看看吧2017-03-03
從0到1學SpringCloud之SpringCloud?gateway網(wǎng)關路由配置示例詳解
Spring?Cloud?Gateway的目標提供統(tǒng)一的路由方式且基于Filter?鏈的方式提供了網(wǎng)關基本的功能,?例如:安全、監(jiān)控、指標和限流?,這篇文章主要介紹了從0到1學SpringCloud之SpringCloud?gateway網(wǎng)關路由配置示例詳解,需要的朋友可以參考下2023-04-04
Java HashMap三種循環(huán)遍歷方式及其性能對比實例分析
這篇文章主要介紹了Java HashMap三種循環(huán)遍歷方式及其性能對比,結合具體實例形式分析了Java HashMap三種循環(huán)遍歷方式的實現(xiàn)方法、運行效率及性能優(yōu)劣,需要的朋友可以參考下2019-10-10
SpringBoot高并發(fā)下控制限流的幾種實現(xiàn)方法
隨著業(yè)務的發(fā)展,高并發(fā)成為很多系統(tǒng)不得不面對的問題,限流作為一種常用的技術手段,可以幫助我們有效地控制請求的流量,避免系統(tǒng)因過載而崩潰,本文將介紹在Spring Boot應用中實現(xiàn)限流的幾種方法,需要的朋友可以參考下2024-06-06

