Java中各種集合的異同與使用


Collection< E >是所有集合類的祖先 我們從這個類往下延伸

1.List


不同點:

名稱 數據結構 安全性 插入和刪除(時間複雜度) getIndex 內存空間佔用
ArrayList 數組 非同步,不安全 首尾O(1),index O(n-i)) 高效 結尾會預留一定的空間
LinkedList 雙向鏈表 非同步,不安全 O(n) 較慢 每一個元素都耗時
Vector(淘汰) 數 組 線程安全(synchronized) ----- ----- -----
  • ArrayList增刪沒有想象中慢,ArrayList的增刪底層調用的copyOf()被優化過,加上現代CPU對內存可以塊操作,普通大小的ArrayList增刪比LinkedList更快。

2.Set

  • HashSet
  • LinkedHashSet
  • TreeSet

不同點:

名稱 順序 基礎
HashSet 無序 基於HashMap
LinkedHashSet 自動排序 基於TreeMap
TreeSet 維護“插入順序” 基於HashSet,是HashSet的擴展
  • Set不允許包含相同的元素,如果試圖把兩個相同元素加入同一個集合中,add方法返回false

3.Map

不同點:

名稱 實現 繼承 是否允許null值 擴容方式 存儲方式
HashMap 實現Map接口 繼承 AbstractMap 類 允許key和value爲null值 size*2,且size必定爲2^n 1.如果衝突數量於8,則是以鏈表方式解決衝突。2.如果當衝突大於等於8時,就會將衝突的Entry轉換爲紅黑樹進行存儲。3如果當數量小於6時,則又轉化爲鏈表存儲。
HashTable 實現Map接口 繼承 Dictionary類 鍵值對都不能爲空 size*2+1 鏈表方式存儲
LinkedHashMap 實現Map接口 繼承 HashMap類 允許key和value爲null值 基於拉鍊式散列結構即由數組和鏈表或紅黑樹組成
TreeMap 實現NavigableMap接口 繼承 AbstractMap類 不允許Key爲null 紅黑樹(自平衡的排序二叉樹)

已上是常見集合的梳理,但是在多線程環境下 , Vector被淘汰 , 使用synchronizedList又過於笨重

4. JUC下常用的幾個線程安全容器

安全容器詳解入口

1. CopyOnWriteArrayList

CopyOnWriteArrayList博客入口

2. CopyOnWriteArraySet

同CopyOnWriteArrayList

3. ConcurrentLinkedQueue

ConcurrentLinkedQueue

4. ConcurrentSkipListMap

ConcurrentSkipListMap

5. ConcurrentHashMap

ConcurrentHashMap博客入口

因爲HashTable也是線程安全的,總結一下不同點:

  • 底層數據結構:
    • JDK1.7的 ConcurrentHashMap 底層採用 分段的數組+鏈表 實現,JDK1.8 採用的數據結構跟HashMap1.8的結構一樣,數組+鏈表/紅黑二叉樹。
    • Hashtable 和 JDK1.8 之前的 HashMap 的底層數據結構類似都是採用 數組+鏈表 的形式,數組是 HashMap 的主體,鏈表則是主要爲了解決哈希衝突而存在的;
  • 實現線程安全的方式(重要):
    • ① 在JDK1.7的時候,ConcurrentHashMap(分段鎖) 對整個桶數組進行了分割分段(Segment),每一把鎖只鎖容器其中一部分數據,多線程訪問容器裏不同數據段的數據,就不會存在鎖競爭,提高併發訪問率。 到了 JDK1.8 的時候已經摒棄了Segment的概念,而是直接用 Node 數組+鏈表+紅黑樹的數據結構來實現,併發控制使用 synchronized 和 CAS 來操作。(JDK1.6以後 對 synchronized鎖做了很多優化) 整個看起來就像是優化過且線程安全的 HashMap,雖然在JDK1.8中還能看到 Segment 的數據結構,但是已經簡化了屬性,只是爲了兼容舊版本;
    • ② Hashtable(同一把鎖) :使用 synchronized 來保證線程安全,效率非常低下。當一個線程訪問同步方 法時,其他線程也訪問同步方法,可能會進入阻塞或輪詢狀態,如使用 put 添加元素,另一個線程不能使用 put 添加元素,也不能使用 get,競爭會越來越激烈效率越低。

如何選用集合?

主要根據集合的特點來選用,比如我們需要根據鍵值獲取到元素值時就選用Map接口下的集合,
需要排序時選擇TreeMap,不需要排序時就選擇HashMap,需要保證線程安全就選用ConcurrentHashMap.
當我們只需要存放元素值時,就選擇實現Collection接口的集合,
需要保證元素唯一時選擇實現Set接口的集合比如TreeSet或HashSet,
不需要就選擇實現List接口的比如ArrayList或LinkedList,
然後再根據實現這些接口的集合的特點來選用。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章