【Java集合源碼分析】關於Java集合你需要知道的是什麼

前言

Java集合估計是我們開發過程中,用的最多的API了,它位於java.util包下,同時支持多線程的集合類位於java.util.concurrent包下。

我們都知道各種數據結構最底層的組成都是數組或者鏈表,其實各種集合類也是基於最基本的數據結構進行封裝,便於各種場景直接使用。

我們可以把集合想象成一個容器,它可以存儲各種對象,擴展和封裝了數組和鏈表,通過算法實現。

有了這些認識,是不是集合也變了沒那麼抽象了,後續將陸續更新各種常見集合類的底層實現。—慢慢更新

------萬變不離其宗,各種集合就像各門各派的招式,但是其本質都是數據結構和算法。

好吧,這是一個不那麼合適的比喻。天下武功,唯快不破,透過事物的本質,方能笑傲江湖…扯遠了,能不被各路面試官虐慘就心滿意足了…

集合框架

Java集合類主要由兩個根接口Collection和Map派生出來的,Collection派生出了三個子接口:List、Set、Queue,這4個接口又分別衍生出了很多的實現類。

孫猴子毫毛一吹,子孫千千萬?

Collection接口的主要子類關係,如下圖所示:

Collection相當於容納了其他對象的引用,而構成了一個集合的對象,整個集合可以有序的,也可以無序的,它本身不能被直接實現,需要去實現它的子接口如:List,Set。

List接口是一個有序的Collection,能夠精準的控制列表中每個元素的插入位置,能夠通過索引來訪問List中的元素(List中的元素位置,類似數組下標,第一個元素位置爲0),允許有相同的元素,且允許null。

常見的實現:ArrayList(查詢快)、LinkedList(增刪快)。傳送門:【Java集合】ArrayList源碼解析【Java集合】LinkedList源碼解析

喂喂,不是還有另外一個兒子Vector嗎,對不起,他已經被後浪排在沙灘上了…

Queue接口以隊列實現了Collection,隊列當然滿足一定的隊列順序了,除了優先隊列外,都是滿足FIFO(先進先出)方式排序元素。Queue實現通常不允許插入null元素,因爲null經常被poll方法用做識別隊列是否包含元素。

常見的實現:PriorityQueue(優先隊列),你期待的傳送門還沒開啓…

Set接口具有和Collection完全一樣的接口,只是行爲上不同,Set不保存重複元素,且對象是唯一的。

常見的實現:HashSet(由Hash表實現)、LinkedHashSet(由鏈表和Hash表實現)、TreeSet(有序的Set),你期待的傳送門還沒開啓…

在這裏插入圖片描述

看完Collection:列表,我們再來看看Map:圖,以key-value鍵值對映射關係存儲元素。

Map接口的主要子類關係,如下圖所示:

將key映射到value的對象,不能包含重複元素,每個key最多映射一個value。

Map實現的類較多:HashMap、HashTable、SortedMap、LinkedHashMap、TreeMap等。你期待的傳送門還沒開啓…

在這裏插入圖片描述

看到這裏,應該對Java集合有了整體宏觀的認識,你肯定會問:後宮三千,我該選哪個好呢?…醒醒,天亮了

List和Set的區別

  1. List接口實例存儲是有序的,可以重複的元素;Set接口實例存儲的是無序的,不重複的數據;
  2. List和數組類似,可以動態增長,根據實際存儲的數據長度自動增長List的長度。查找元素效率高(直接通過索引),插入刪除效率低(因爲會引起其他元素位置變動);
  3. Set查詢效率低下,刪除和插入效率高,插入和刪除不會引起元素位置的變化。

常見的集合實現類

  1. ArrayList:實現了可變大小的數組,可以隨機訪問和遍歷元素;非同步類;動態增長當前長度的50%;插入刪除效率低(會引起其他元素位置變動)。
  2. LinkedList:主要用於創建鏈表數據結構,沒有同步方法,需要手動加鎖。
  3. HashSet:不允許出現重複元素,集合中元素是無序的;允許爲null,但最多一個;不同步,需要手動加鎖。
  4. LinkedHashSet:具有可預知迭代順序的Set接口的哈希表和鏈接列表實現。
  5. TreeSet:可以實現排序的Set集合。
  6. HashMap:散列表,存儲的內容是key-value,根據key的HashCode值存儲數據,具有快速訪問速度;最多允許一個記錄的key爲null;不支持線程同步。
  7. TreeMap:使用了紅黑樹來實現的Map,不同步。
  8. WeakHashMap:使用弱密鑰的哈希表,不同步。
  9. LinkedHashMap:使用元素的自然順序對元素進行排序,不同步。
  10. IdentityHashMap:比較鍵(和值)時使用引用相等代替對象相等。

線程安全集合類

前面講的集合類好像都是非安全的,那麼安全的集合類有哪些呢?

1.CopyOnWriteArrayList

1)線程安全的List,修改方法(add,set,remove等)都通過集合屬性一個ReentrantLock進行同步,先獲取鎖,才能執行變更操作。但是通過ReentrantLock進行同步只是能保證線程的安全,並不能保持時間上的有序和正確,因爲先申請鎖然後進入休眠等待的線程,並不一定是最先獲取鎖的線程,所以,會在時間順序看,對集合的修改是無序的。
2)對象數組用volatile修飾,其他線程對集合元素數組的修改,能夠在其他線程的每次訪問都是最新值。
3)在對集合元素數組進行修改時,是先拷貝之前的元素數組出一個新元素數組,在新的元素數組上進行修改,修改完畢後在用元素數組替換舊的元素數組,內存消耗大。

2.ConcurrentSkipListSet

ConcurrentSkipListSet是實現了NavigableSet接口和繼承自AbstractSet的Set集合類,它是線程安全的,內部存儲實際是存在ConcurrentNavigableMap中。內部元素的存儲是有序的,根據創建ConcurrentSkipListSet時提供的Comparator。

3.CopyOnWriteArraySet

CopyOnWriteArraySet底層實現是CopyOnWriteArrayList,線程安全的,大部分操作和原理是同CopyOnWriteArrayList。

4.ConcurrentHashMap

ConcurrentHashMap是線程安全的HashMap,實現了ConcurrentMap接口,所以提供了一些原子性和線程安全的集合操作接口。
JDK1.8之後的ConcurrentHashMap的實現和1.7之前已經大不一樣了,保證線程安全的機制從原來的給每個數組segment加鎖方式變成了無鎖的cas操作,特別是擴容方式被重寫了,實現了無鎖情況下多線程參與複製舊存儲元素到新存儲集合上。有一個最重要的不同點就是ConcurrentHashMap不允許key或value爲null值。

5.HashTable

HashTable是線程安全的HashMap,其實就在修改方法上添加synchronized關鍵字進行同步,同步的粒度太大,性能不佳,不建議使用。

6.ConcurrentSkipListMap

ConcurrentSkipListMap是基於SkipList存儲結構實現的線程安全的有序Map集合,不支持Null爲value或者爲key,線程安全且有序。

迭代器和比較器

迭代器(Iterator接口)提供了一種方法,來對集合、容器進行遍歷的方式,使你能夠通過循環來得到換刪除集合元素。
ListIterator接口繼承於Iterator接口,允許雙向遍歷列表和修改元素。

比較器(Comparator接口),集合實現Comparator接口,就可以按照你定義的排序方式進行排序。

小結

後續會深入各個集合類的源代碼進行分析學習,敬請期待…
【Java集合】ArrayList源碼解析
【Java集合】LinkedList源碼解析

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章