1. 程式人生 > >Java容器框架(一)--概述篇

Java容器框架(一)--概述篇

1. 概述

在Java開發中,我們經常使用到一些容器類例如ArrayList、HashMap等,很少去了解其他一些容器類或者說對Java容器有一個整體的瞭解。於是趁此閒暇之際,對Java容器進行一個整體的描述,一方面是為了對Java容器能有一個整體的思維,另一方面也是為了在平常工作中能夠通過不同的場景對容器類的使用做到遊刃有餘。

我們知道Java容器類基本上都是在java.util包下,有一個Collection介面,它是Java容器的頂級介面(除了Map),在編輯器中開啟Collection介面,然後快捷鍵(IDEA預設是Ctrl+h)檢視該介面的實現類,可以看到在util包下有List、Set和Queue三大介面,Java容器中大部分類都實現了這三大介面中的一個或多個,容器中除了這三大介面,當然還有另一個重要的介面了即Map。因此Java容器的最頂層結構如下圖:

下面我會對這四大介面及下面的子類做一個詳細的介紹,在介紹之前,允許我借用網上一張圖片,能夠對容器類有一個大致的輪廓(圖中暫時確實map系列,在介紹map的時候會給對應的類圖)。

2. List集合

List集合,通過名字大概能夠猜測到它是一個線性結構的列表,學過資料結構都知道線性表有兩種儲存方式即順序儲存(陣列)和鏈式儲存(連結串列),其實List集合正式這種線性結構集合的實現,List集合它是一個存放可重複、無序(不會對存放的資料進行排序)的線性結構資料集合。

通過同樣的方法在編輯器中開啟List介面,檢視其實現類,可以看到大致有如下實現類:AbstractList、ArrayList、Vector、LinkedList、CopyOnWriteArrayList(多執行緒中)。List容器類結構圖大致如下:

那麼問題來了,List容器這些子類都有些什麼作用呢?

此處只是簡單介紹List子類的一些作用或實現原理,並不從原始碼角度進行分析,在之後的文章中會對部分子類進行原始碼分析。

  • AbstractList

看類名就能過猜測到該類為一個抽象類,它繼承自AbstractCollection類實現了List介面,是 ArrayList 和 AbstractSequentiaList 的父類。內部實現了List的部分方法,同時也提供了Iterator, ListIterator 迭代器的實現類,分別為 Itr, ListItr。ListItr繼承自Itr,從某種角度可以視為Itr的擴充套件。詳情可以參見

Java 集合深入理解(6):AbstractList

  • ArrayList

該類相信大家再熟悉不過,繼承自AbstractList抽象類,實現List、RandomAccess等介面,內部是由陣列實現,容量大小不固定,元素的順序和存放的順序一致,遍歷元素可以通過隨機讀寫(RandomAccess)和迭代器(Iterator)兩種方式,由於陣列的特性,當然RandomAccess方式要由於Iterator。

  • LinkedList

在List家族,除了對ArrayList非常熟悉之外,估計就到LinkedList了。LinkedList基於雙向連結串列實現,非常適用於資料插入和刪除,對資料遍歷較慢,和ArrayList恰好相反。

  • Vector

Vector 和 ArrayList 一樣,也是基於陣列來實現,區別是Vector是執行緒安全的,通過原始碼可以看到Vector很多方法都是使用synchronized來修飾。

  • Stack

通過類名可以知道該類實現了棧的功能,Stack繼承自Vector,因此也是由陣列來實現,並且執行緒安全。

  • CopyOnWriteArrayList

該類是併發容器(java.util.concurrent)中的類,它的原理是當我們向容器中新增元素的時候,不直接往當前容器新增,而是先將當前容器進行Copy,複製出一個新的容器,然後新的容器裡新增元素,新增完元素之後,再將原容器的引用指向新的容器。這樣的意義主要在於當併發讀取容器內容時不需要加鎖,但是寫內容的時候需要保證同步並且需要開闢新的記憶體空間,因此比較適合讀多寫少的併發場景。

3. Set集合

什麼是Set集合,它有什麼特性?

先來看看程式碼中的英文說明:

A collection that contains no duplicate elements.  More formally, sets contain no pair of elements <code>e1</code> and <code>e2</code> such that <code>e1.equals(e2)</code>, and at most one null element. 

大概意思就是:該集合中存放一些不能重複的元素。正式一點來說,就是不能存在這樣一對元素(例如:e1.equals(e2)返回為true),並且容器中最對可以有一個為null的元素。

Set集合下的類大致有:SortedSet(介面)、AbstractSet(抽象類)、HashSet、LinkedHashSet、NavigableSet(介面)、TreeSet等等,如下圖所示:

我們一起來了解了解這些介面或類所具有的作用。

  • AbstractSet

AbstractSet之餘Set很類似於AbstractList之餘List,主要起著一個骨架的作用,它繼承AbstractCollection,實現Set介面,它其實僅僅只實現了equals、hasCode、removeAll三個方法。

  • HashSet

我們首先看看類結構:

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

繼承自AbstractSet,實現了Set介面,它內部程式碼並不多,使用HashMap來儲存資料。當對HashSet新增一個元素E時,其實就是向HashMap中新增一個鍵值對,鍵就是E,值為一個通用的Object物件,這也就很能理解HashSet不能存放相同元素的原因了吧,同時也可以 知道訪問的順序和插入的順序有可能是不一樣的。

  • LinkedHashSet

類結構如下:

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

LinkedHashSet繼承自HashSet,呼叫的構造器其實就是HashSet的構造器,只不過它是用LinkedHashMap來儲存資料,因此它的特性和LinkedHashMap很相似,可以保證遍歷順序序和插入順序序一致。

  • SortedSet&NavigableSet

Set容器本身沒有排序能力,當類實現了SortedSet或NavigableSet介面,則提供了排序方案。

  • TreeSet

TreeSet類結構如下:

public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, java.io.Serializable

實現了NavigableSet,由於NavigableSet繼承自SortedSet,因此TreeSet具有排序的功能。TreeSet內部使用NavigableMap來存放資料,預設情況下,是使用TreeMap來儲存資料,因此它的特性和TreeMap的特性是很類似的。

通過對Set集合的瞭解,我們發現Set的子類與Map的子類有這千絲萬縷的關係,要知道Set子類的實現原理必當先了解Map子類的實現原理,下面我們來大概瞭解下Map家族。

4. Map集合

先一言不合來張Map類圖:

看看函式的命名,有沒有發現與Set裡面很相似(當然我更加相信是Set是參考Map),下面對Map家族稍作了解。

  • Map:鍵值對對映的介面,該對映不包括重複的鍵,一個鍵對應一個值。
  • SortedMap:有序的鍵值對介面,繼承Map介面。
  • NavigableMap:繼承SortedMap,具有針對給定搜尋目標返回最接近匹配項的導航方法的介面。
  • AbstractMap:實現了Map中的絕大部分函式介面,它減少了Map的實現類的重複編碼。
  • TreeMap: 有序散列表,實現SortedMap 介面,底層通過紅黑樹實現。
  • Dictionary:任何可將鍵對映到相應值的類的抽象父類。
  • HashTable: 基於“拉鍊法”實現的散列表,多執行緒安全,大部分方法都是使用synchronized修飾的。
  • HashMap: 是基於“拉鍊法”實現的散列表,底層採用“陣列+連結串列”實現。
  • LinkedHashMap: HashMap無法保證資料的存與取順序一致,LinkedHashMap正式彌補了這樣的缺點,內部通過維護一條雙向迴圈連結串列來保證資料的插入和訪問順序。
  • WeakHashMap:基於“拉鍊法”實現的散列表,和HashMap不同的是它儲存的鍵都是弱鍵,也就是說對映的存在並不阻止對鍵進行垃圾回收,鍵沒有值自然也丟棄。
  • ConcurrentHashMap:該類是在java.util.concurrent包中,主要是考慮多執行緒安全的情況,我們都知道HashMap多執行緒是不安全的,而HashTable雖然多執行緒安全但是效率太低,於是就出現了ConcurrentHashMap。它是採用鎖分段技術保證執行緒安全。

未完待續。。。

參考文獻