本章主要總結了集合的一些基礎但有重點的知識點,例如他們的底層資料結構以及集合之間的區別,其中 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 內部使用了連結串列來維護元素的插入順序。
這些知識點如果都能自己開啟原始碼配合看一下,很多有關集合的面試題就可以應付了。
最後推廣下我的公眾號:苦逼的碼農:戳我即可關注,文章都會首發於我的公眾號,期待各路英雄的關注交流。