關於集合中一些常考的知識點總結

帥地發表於2019-03-10

本章主要總結了集合的一些基礎但有重點的知識點,例如他們的底層資料結構以及集合之間的區別,其中 HashMap 最為重點。

集合

Java的集合框架中可以分為兩大類:第一類是按照單個元素儲存的 Collection 集合,其中 Set, List, Queue 都實現了 Collection 介面。第二類是按照 Key-Value 儲存的 Map 集合。

List

List常量的兩個子類分別是 ArrayList 和 LinkedList 這兩個集合。

(1)、ArrayList 的特點。

A. ArrayList 底層資料結構是陣列,陣列的特點就是可以快速隨機訪問,直接根據下標定位,缺點是插入和刪除速度比較慢,需要移動元素。

B. ArrayList 每次擴容之後的大小為之前的 1.5 倍。預設初始容量大小為 10。

(2)、LinkedList 的特點

LinkedList 底層資料結構是雙向連結串列,連結串列的特點就是隨機訪問速度慢,必須一個一個遍歷,不能直接通過下標定位,不過在插入、刪除方面速度就比較快。不過由於連結串列是記憶體分配不要求連續,記憶體的利用率比較高。

LinkedList 還實現了另外一個介面Deque,即 double-ended queue,使得 LinkedList 同時具有佇列的特性。

(3)、vector 的特點

vector 和 ArrayList 基本一樣,不過 Vector 是執行緒安全的,而 ArrayList 是執行緒不安全的,

ArrayList 和 LinkedList 都是執行緒不安全的集合。

Map

Map 是一種 key-value 的集合,其常用的集合實現類有 HashMap, HashTable, TreeMap。

(1)、HashMap(重重點)

HashMap 的底層資料結構是 連結串列 + 陣列,如果對他的底層結構不大懂的可以看我之前寫的一篇文章:HashMap的存取原理你知道多少

HashMap 在進行 put 操作時,允許 key 和 value 為 null,且是執行緒不安全的,所以 HashMap 的效能非常好,只不過在多執行緒的環境下使用,需要給他加上對應的鎖

重點資料:HashMap 的預設容量為 capacity = 16, 預設擴容因子 loadFactor = 0.75,至於擴容因子有什麼用,下面會涉及到。

不過需要注意的是,HashMap 內部用變數 threshold 變數來表示 HashMap 中能放入的元素個數,且在 threshold 不超過最大值前提下, threshold = loadFactor * capacity。

也就是說,當元素的個數達到 threshold 之後,就會觸發 HashMap 的擴容,而不是達到 capacity 才觸發擴容。每次擴容之後的容量為之前的 2 倍

而 ArrayList 則是元素達到 capacity 時才觸發擴容。

還有一個需要注意的是,HashMap 容量並不會在 new 的時候分配,而是在第一次 put 的時候才完成建立的。

public V put(K key, V value){
    if(table == EMPTY_TABLE){
        // 初始化
        inflateTable(threshold);
    }
}

預設初始化容量大小 capacity = 16,如果我們在初始化的時候指定了容量的大小 initialCapacity,則會先計算出比 initialCapacity 大的 2 的冪存入 threshold,並且也會把初始化容量置為 capacity = threshold。例如當我們指定初始容量 initialCapacity = 26 的話,則 threshold = 32, capacity = 32。

(2)、HashTable的特點

a. HashTable 和 HashMap 在工作原理上幾乎一樣,不過 HashTable 是執行緒安全的,如圖

關於集合中一些常考的知識點總結

不過鎖是直接加在方法外面,所以在多執行緒環境下,效能極差。

不過在多執行緒的環境下,我們優先使用 ConcurrentHashMap 集合,這個集合在工作原理上也幾乎和前面兩個一樣,但它是執行緒安全的,並且不像 HashTable 那樣,把整個方法都給加鎖了,而是把方法裡面的關鍵程式碼加鎖了,如圖:

關於集合中一些常考的知識點總結

所以在處理速度上比較快。

b. HashTable 不允許 key 和 value 為 null。

c. HashMap 的迭代器是 fail-fast 機制(快速失敗機制), 而 HashTable 則是 fail-safe 機制(快速安全),如果不知道 fail-fast 與 fail-safe 的,可以看我之前寫 的一篇文章:談談fail-fast與fail-safe

(3)、LinkedHashMap 的特點

LinkedHashMap 是 HashMap 的一個子類,我們知道 HashMap是在插入的時候是根據雜湊碼來選擇位置的,是無序的,而 LinkedHashMap 在插入的時候具有雙向連結串列的特性,內部使用連結串列維護了插入的順序,能夠保證輸出的順序和輸入時的相同。

LinkedHashMap 也是執行緒不安全的,並且允許 key-value 為 null。

(4)、TreeMap

TreesMap 的底層資料結構是紅黑樹,和 HashMap 不同,它的 get, put, remove 操作都是 O(logn) 的時間複雜度,並且元素是有序的。

同樣,TreeMap 也是執行緒不安全的。

Set

Set 是一種不允許出現重複元素的集合型別,常用的三個實現類是 HashSet、TreeSet 和 LinkedHashSet。

(1)、HashSet

HashSet 實際上是用 HashMap 來實現的,如圖

關於集合中一些常考的知識點總結

只是 Value 被固定為一個靜態物件

關於集合中一些常考的知識點總結

使用 Key 來保證集合元素的唯一性,不過它不保證集合元素的順序。

(2)、TreeSet

TreeSet 也是用 TreeMap 來實現的,底層為樹結構,TreeSet 則能夠保證集合元素是有序的。

(3)、LinkedHashSet

LinkedHashSet 繼承 HashSet,具有 HashSet 優點,不過與 HashSet 不同的是,LinkedHashSet 內部使用了連結串列來維護元素的插入順序。

這些知識點如果都能自己開啟原始碼配合看一下,很多有關集合的面試題就可以應付了。

最後推廣下我的公眾號:苦逼的碼農戳我即可關注,文章都會首發於我的公眾號,期待各路英雄的關注交流。

相關文章