Java集合框架學習

席潤發表於2019-02-18

簡介

JDK1.2 引入了 Java 集合框架,包含一組資料結構。所有這些資料結構在 java.util 包裡,包含了 Collection、List、Set、Map、SortedMap 介面。這些介面的實現類有 LinkedList、TreeSet、ArrayList、HashMap 等。

JDK1.8原始碼

Java 集合框架主要包括兩種型別的容器,一種是集合(Collection),儲存一個元素集合,另一種是圖(Map),儲存鍵/值對對映。

java集合框架

集合框架是一個用來代表和操縱集合的統一架構。所有的集合框架都包含如下內容:

  • **介面:**是代表集合的抽象資料型別。例如 Collection、List、Set、Map 等。之所以定義多個介面,是為了以不同的方式操作集合物件
  • **實現(類):**是集合介面的具體實現。從本質上講,它們是可重複使用的資料結構,例如:ArrayList、LinkedList、HashSet、HashMap。
  • **演算法:**是實現集合介面的物件裡的方法執行的一些有用的計算,例如:搜尋和排序。這些演算法被稱為多型,那是因為相同的方法可以在相似的介面上有著不同的實現。

常用集合介面

Collection 是最基本的集合介面,一個 Collection 代表一組 Object,即 Collection 的元素, Java不提供直接繼承自Collection的類,只提供繼承於的子介面(如List和set)。Collection 介面儲存一組***不唯一***,***無序***的物件。

List介面是一個有序的 Collection,使用此介面能夠精確的控制每個元素插入的位置,能夠通過索引(元素在List中位置,類似於陣列的下標)來訪問List中的元素,第一個元素的索引為 0,而且允許有相同的元素。List 介面儲存一組***不唯一***,有序(插入順序)的物件。

Set 具有與 Collection 完全一樣的介面,只是行為上不同,Set 不儲存重複的元素。Set 介面儲存一組***唯一***,***無序***的物件。

Map 介面儲存一組***鍵值物件***,提供key(鍵)到value(值)的對映。

常用集合實現類

LinkedList

該類實現了List介面,允許有null(空)元素。主要用於建立連結串列資料結構,該類沒有同步方法,如果多個執行緒同時訪問一個List,則必須自己實現訪問同步,解決方法就是在建立List時候構造一個同步的List。例如:

Listlist=Collections.synchronizedList(newLinkedList(...));
複製程式碼

LinkedList 查詢效率低。

ArrayList 該類也是實現了List的介面,實現了可變大小的陣列,隨機訪問和遍歷元素時,提供更好的效能。該類也是非同步的,在多執行緒的情況下不要使用。ArrayList 增長當前長度的50%,插入刪除效率低。

Vector

該類和ArrayList非常相似,但是該類是同步的,可以用在多執行緒的情況,該類允許設定預設的增長長度,預設擴容方式為原來的2倍。

HashSet

該類實現了Set介面,不允許出現重複元素,不保證集合中元素的順序,允許包含值為null的元素,但最多隻能一個。

HashMap

HashMap 是一個雜湊表,它儲存的內容是鍵值對(key-value)對映。 該類實現了Map介面,根據鍵的HashCode值儲存資料,具有很快的訪問速度,最多允許一條記錄的鍵為null,不支援執行緒同步。

Set和List的區別

  • Set 介面例項儲存的是無序的,不重複的資料。List 介面例項儲存的是有序的,可以重複的元素。
  • Set檢索效率低下,刪除和插入效率高,插入和刪除不會引起元素位置改變 <實現類有HashSet,TreeSet>
  • List和陣列類似,可以動態增長,根據實際儲存的資料的長度自動增長List的長度。查詢元素效率高,插入刪除效率低,因為會引起其他元素位置改變 <實現類有ArrayList,LinkedList,Vector>

注意

在Java中任何集合中存放的都是物件,即引用資料型別,基本資料型別不能放到集合中。將基本資料型別放到集合中,這個過程中發生了自動裝箱,從集合中取出了基本資料型別,因為這個過程發生了自動拆箱。裝箱就是自動將基本資料型別轉換為包裝器型別;拆箱就是自動將包裝器型別轉換為基本資料型別

List介面

List是介面不能例項化,可以使用其實現類來例項List型別集合變數。例:

List list = new ArrayList();

實現類
ArrayList

ArrayList是基於動態陣列資料結構的實現,訪問元素速度優於LinkedList。

以陣列實現。節約空間,但陣列有容量限制。超出限制時會增加 50% 容量,用System.arraycopy()複製到新的陣列,因此最好能給出陣列大小的預估值。預設第一次插入元素時建立大小為 10 的陣列。擴容增量:原容量的 0.5倍 + 1

LinkedList

LinkedList是基於連結串列資料結構的實現,在批量插入或刪除資料時優於ArrayList,但佔用的記憶體空間比較大。

以雙向連結串列實現。連結串列無容量限制,但雙向連結串列本身使用了更多空間,也需要額外的連結串列指標操作。

Vector

Vector類實現了一個動態陣列。初始容量為 10 ,載入因子為 1,擴容增量:原容量的 1倍 。和 ArrayList 很相似,但是兩者是不同的:

  • Vector 是同步訪問的。
  • Vector 包含了許多傳統的方法,這些方法不屬於集合框架。

Vector 類支援 4 種構造方法。

Vector() //建立一個預設的向量,預設大小為 10
複製程式碼
Vector(int size) //建立指定大小的向量
複製程式碼
Vector(int size,int incr) //建立指定大小的向量,並且增量(表示向量每次增加的元素數目)用incr指定。
複製程式碼
Vector(Collection c) //建立一個包含集合 c 元素的向量
複製程式碼
常用方法

List介面繼承自Collection介面,List介面中的很多方法都繼承自Collection介面的。List介面中常用方法如下。

1.操作元素

  • get(int index):返回List集合中指定位置的元素。
  • set(int index, Object element):用指定元素替換List集合中指定位置的元素。
  • add(Object element):在List集合的尾部新增指定的元素。該方法是從Collection集合繼承過來的。
  • add(int index, Object element):在List集合的指定位置插入指定元素。
  • remove(int index):移除List集合中指定位置的元素。
  • remove(Object element):如果List集合中存在指定元素,則從List集合中移除第一次出現的指定元素。該方法是從Collection集合繼承過來的。
  • clear():從List集合中移除所有元素。該方法是從Collection集合繼承過來的。

2.判斷元素

  • isEmpty():判斷List集合中是否有元素,沒有返回true,有返回false。該方法是從Collection繼承過來的。
  • contains(Object element):判斷List集合中是否包含指定元素,包含返回true,不包含返回false。該方法是從Collection集合繼承過來的。

3.查詢元素

  • indexOf(Object o):從前往後查詢List集合元素,返回第一次出現指定元素的索引,如果此列表不包含該元素,則返回-1。
  • lastIndexOf(Object o):從後往前查詢List集合元素,返回第一次出現指定元素的索引,如果此列表不包含該元素,則返回-1。

4.其它

  • iterator():返回迭代器(Iterator)物件,迭代器物件用於遍歷集合。該方法是從Collection繼承過來的。
  • size():返回List集合中的元素數,返回值是int型別。該方法是從Collection集合繼承過來的。
  • subList(int fromIndex, int toIndex):返回List集合中指定的 fromIndex(包括 )和 toIndex(不包括)之間的元素集合,返回值為List集合。
遍歷集合

  集合最常用的操作之一是遍歷,遍歷就是將集合中的每一個元素取出來,進行操作或計算。List集合遍歷有三種方法:

  1. 使用for迴圈遍歷:List集合可以使用for迴圈進行遍歷,for迴圈中有迴圈變數,通過迴圈變數可以訪問List集合中的元素。
  2. 使用for-each迴圈遍歷:for-each迴圈是針對遍歷各種型別集合而推出的,筆者推薦使用這種遍歷方法。
  3. 使用迭代器遍歷:Java提供了多種迭代器,List集合可以使用Iterator和ListIterator迭代器。
// 使用迭代器遍歷
Iterator it = list.iterator();                           
while (it.hasNext()) {                                   
    Object item = it.next();                             
    String s = (String) item;                            
    System.out.println("讀取集合元素: " + s);
}
複製程式碼

:使用for-each迴圈遍歷和使用迭代器遍歷從集合中取出的元素都是Object型別。

Set介面

Set是介面不能例項化,可以使用其實現類來例項List型別集合變數。例:

Set set = new HashSet();

Set集合是由一串無序的,不能重複的相同型別元素構成的集合。

當不考慮順序,且沒有重複元素時,Set集合和List集合可以互相替換的。

Set幾乎都是內部用一個Map來實現, 因為Map裡的KeySet就是一個Set,而value是假值,全部使用同一個Object。Set的特徵也繼承了那些內部Map實現的特徵。

實現類
HashSet

繼承Set介面,儲存的是無序,唯一的物件。HashSet使用equals來進行物件對比,確定資料是唯一的,如果兩個資料的物件是一致的,那麼HashSet將會把這兩個合併,只儲存一個空間。內部是HashMap來實現。初始容量為 16,載入因子為 0.75 ,擴容增量:原容量的 1倍

TreeSet

TreeSet 是一個有序的集合,它的作用是提供有序的Set集合。它繼承於AbstractSet抽象類,實現了NavigableSet, Cloneable, java.io.Serializable介面。 TreeSet 繼承於AbstractSet,所以它是一個Set集合,具有Set的屬性和方法。 TreeSet 實現了NavigableSet介面,意味著它支援一系列的導航方法。比如查詢與指定目標最匹配項。 TreeSet 實現了Cloneable介面,意味著它能被克隆。 TreeSet 實現了java.io.Serializable介面,意味著它支援序列化。

TreeSet是基於TreeMap實現的。TreeSet中的元素支援2種排序方式:自然排序 或者 根據建立TreeSet 時提供的 Comparator 進行排序。這取決於使用的構造方法。 TreeSet為基本操作(add、remove 和 contains)提供受保證的 log(n) 時間開銷。 另外,TreeSet是非同步的。 它的iterator 方法返回的迭代器是fail-fast的。

詳見

常用方法

Set介面也繼承自Collection介面,Set介面中大部分都是繼承自Collection介面,這些方法如下。

1.操作元素

  • add(Object element):在Set集合的尾部新增指定的元素。該方法是從Collection集合繼承過來的。
  • remove(Object element):如果Set集合中存在指定元素,該方法是從Collection集合繼承過來的。
  • clear():從Set集合中移除所有元素。該方法是從Collection集合繼承過來的。

2.判斷元素

  • isEmpty():判斷Set集合中是否有元素,沒有返回true,有返回false。該方法是從Collection集合繼承過來的
  • contains(Object element):判斷Set集合中是否包含指定元素,包含返回true,不包含返回false。該方法是從Collection集合繼承過來的。

3.其他

  • iterator():返回迭代器(Iterator)物件,迭代器物件用於遍歷集合。該方法是從Collection集合繼承過來的。
  • size():返回Set集合中的元素數,返回值是int型別。該方法是從Collection集合繼承過來的。
遍歷集合

Set集合中的元素由於沒有序號,所以不能使用for迴圈進行遍歷,但可以使用for-each迴圈迭代器進行遍歷。事實上這兩種遍歷方法也是繼承自Collection集合,也就是說所有的Collection集合型別都有這兩種遍歷方式。

Map介面

  Map(對映)集合表示一種非常複雜的集合,允許按照某個鍵來訪問元素。Map集合是由兩個集合構成的,一個是鍵(key)集合,一個是值(value)集合。鍵集合是Set型別,因此不能有重複的元素。而值集合是Collection型別,可以有重複的元素。Map集合中的鍵和值是成對出現的。

Map是介面不能例項化,可以使用其實現類例項化Map型別集合變數,例:

Map map = new HashMap();

實現類
HashMap

以Entry<K,V>陣列實現的雜湊桶陣列,用Key的雜湊值取模桶陣列的大小可得到陣列下標。

插入元素時,如果兩條Key落在同一個桶((不同的key對應相同的下標)),Entry用一個next屬性實現多個Entry以單向連結串列存放,後入桶的Entry將next指向桶當前的Entry。

hashmap

查詢雜湊值為17的key時,先定位到第一個雜湊桶,然後以連結串列遍歷桶裡所有元素,逐個比較其key值。

在JDK8裡,新增預設為8的閥值,當一個桶裡的Entry超過閥值,就不以單向連結串列而以紅黑樹來存放以加快Key的查詢速度。

HashTable

HashMap一樣,Hashtable 也是一個雜湊表,它儲存的內容是鍵值對(key-value)對映。 Hashtable 繼承於Dictionary,實現了Map、Cloneable、java.io.Serializable介面。 Hashtable 的函式都是同步的,所有的讀寫等操作都進行了鎖(synchronized)保護,這意味著它是執行緒安全的。它的key、value都不可以為null。此外,Hashtable中的對映不是有序的。

Hashtable 的例項有兩個引數影響其效能:初始容量載入因子。容量 是雜湊表中桶 的數量,初始容量 就是雜湊表建立時的容量。注意,雜湊表的狀態為 open:在發生“雜湊衝突”的情況下,單個桶會儲存多個條目,這些條目必須按順序搜尋。載入因子 是對雜湊表在其容量自動增加之前可以達到多滿的一個尺度。初始容量和載入因子這兩個引數只是對該實現的提示。關於何時以及是否呼叫 rehash 方法的具體細節則依賴於該實現。 通常,預設載入因子是 0.75, 這是在時間和空間成本上尋求一種折衷。載入因子過高雖然減少了空間開銷,但同時也增加了查詢某個條目的時間(在大多數 Hashtable 操作中,包括 get 和 put 操作,都反映了這一點)。

Hashtable定義了四個構造方法。第一個是:

Hashtable() //預設構造方法
複製程式碼
Hashtable(int size) //建立指定大小的雜湊表
複製程式碼
Hashtable(int size,float fillRatio) //建立了一個指定大小的雜湊表,並且通過fillRatio指定填充比例,填充比例必須介於0.0和1.0之間,它決定了雜湊表在重新調整大小之前的充滿程度
複製程式碼
Hashtable(Map m) //建立了一個以M中元素為初始化元素的雜湊表。雜湊表的容量被設定為M的兩倍。
複製程式碼
TreeMap

TreeMap 是一個有序的key-value集合,它是通過紅黑樹實現的。 TreeMap 繼承於AbstractMap,所以它是一個Map,即一個key-value集合。 TreeMap 實現了NavigableMap介面,意味著它支援一系列的導航方法。比如返回有序的key集合。 TreeMap 實現了Cloneable介面,意味著它能被克隆。 TreeMap 實現了java.io.Serializable介面,意味著它支援序列化

TreeMap基於紅黑樹(Red-Black tree)實現。該對映根據其鍵的自然順序進行排序,或者根據建立對映時提供的 Comparator 進行排序,具體取決於使用的構造方法。 TreeMap的基本操作 containsKey、get、put 和 remove 的時間複雜度是 log(n) 。 另外,TreeMap是非同步的。 它的iterator 方法返回的迭代器是fail-fastl的。

詳細

常用方法

Map集合中包含兩個集合(鍵和值),所以操作起來比較麻煩,Map介面提供很多方法用來管理和操作集合。主要的方法如下。

1.操作元素

  • get(Object key):返回指定鍵所對應的值;如果Map集合中不包含該鍵值對,則返回null。
  • put(Object key, Object value):指定鍵值對新增到集合中。
  • remove(Object key):移除鍵值對。
  • clear():移除Map集合中所有鍵值對。

2.判斷元素

  • isEmpty():判斷Map集合中是否有鍵值對,沒有返回true,有返回false。
  • containsKey(Object key):判斷鍵集合中是否包含指定元素,包含返回true,不包含返回false。
  • containsValue(Object value):判斷值集合中是否包含指定元素,包含返回true,不包含返回false。

3.檢視集合

  • keySet():返回Map中的所有鍵集合,返回值是Set型別。
  • values():返回Map中的所有值集合,返回值是Collection型別。
  • size():返回Map集合中鍵值對數。
遍歷集合

  Map集合遍歷與List和Set集合不同,Map有兩個集合,因此遍歷時可以只遍歷值的集合,也可以只遍歷鍵的集合,也可以同時遍歷。這些遍歷過程都可以使用for-each迴圈迭代器進行遍歷。

java集合框架

推薦:Java 集合系列

主要參考:

[菜鳥教程][Java集合框架]

[ Java學習基礎 ][Java的物件容器 -- 集合]

相關文章