前言
前一陣子,manager隨口問了我這樣一個問題,我想從Map中按順序取出數據,那我應該用哪一個實現類呀?當時我感覺答案就在我的腦邊,但是就是想不起來了。從這一點看,還是需要溫故而知新的。
最近一直在看《碼出高效——Java開發手冊》這本書,確實是一本好書值得推薦,知識點說的十分通俗易懂,本篇文章,正是參考這本書的。
正文
首先呢,如果想要解決上面的問題,可以使用兩種集合,一種是LinkedHashMap,另一種是TreeMap,兩種的相同與不同之處,我會在下面說到。
集合中的頂層接口,最重要的就是Collection和Map了。
原來我聽大學老師說過這樣一句話,最懂集合的就是迭代器了(Map集合除外,因爲Map是一個特殊的集合)。所以Collection接口實現了Iterable接口,讓繼承了Collection接口的接口,具有可以迭代的能力。
Collection 一共有三個兒子,分別是 List,Set, 和Queue。
List集合
list集合的概念與我們最開始接觸的數組相類似,有明確的第一個與最後一個元素,我們通過迭代器,可以拿到和我們插入的順序的值,一樣的結果,list中我們最常用的就是ArrayList和LinkedList了。list在初始化的時候,建議是要在構造函數中給出長度的。避免擴容可能帶來的效率問題
1.ArrayList
底層通過數組進行實現,但是數組在初始化的時候是需要給出長度的,爲啥ArrayList不用呢,其實ArrayList在初始化的時候,默認長度爲10,但是他會隨着數據的增多進行擴容。每一次擴容是把原來的長度右移一位(大概就是原來長度的一半),舉個簡單的例子,原來的長度爲10,轉化爲2進制就是1010,右移一位就是101,然後再轉化爲十進制就是5。爲什麼這裏特別強調是右移一位,而不是1/2呢,因爲如果原始長度是奇數,會讓人感到困惑。
ArrayList具有查詢速度快,但是插入和刪除速度相對較慢,想象一下這樣的場景,我們有一個size爲10的的list,我們把第二個位置上的值刪掉,那麼後面所有的數據都需要移動。
2.LinkedList
LinkedList使用的是雙向鏈表(在Java中所有鏈表的實現,使用的都是雙向鏈表),相比於ArrayList,插入與刪除速度較快,因爲只需要把指向上一個引用的地址和指向下一個引用的地址進行修改即可,但是相對隨機訪問速度較慢。在內存中,利用率更高,因爲不需要一整塊的內存。
Set集合
Set集合中不允許出現相同的元素,很多人都不明白爲什麼,其實Set集合的本質是Map只不過他的Value放置的是一個靜態的對象。這樣也就解釋通了爲什麼key不能相同了。Set只能使用迭代器,而不能通過index去get具體位置上的元素,也是因爲這個原因。Set中最常用的爲HashSet,LinkedHashSet,以及TreeSet。其中LinkedHashSet和TreeSet在插入後的順序,仍然是有序的。
Queue集合
Queue(隊列),是先進先出的一個特殊的線性表,根據這一種特性,經常被用作數據緩存區,現在比較流行的MQ(消息隊列)也是根據這一特性。
Map集合
Map是以key,value鍵值對組成的哈希結構。Map集合和Collection中關係最密切的要屬Set了(之前在將Set的時候,也有說過)我們通過keySet()方法獲取到所有的key,返回的是一個set集合,可以通過values拿到所有的value,還可以通過entrySet拿到所有的鍵值對。所有Map集合使用起來,靈活度非常的高。
最開始的時候Map集合比較出名的是Hashtable,他是線程安全的,採用了鎖,來保護數據的安全性,但是同時會帶來效率底下的問題,於是便被放棄了。
後來出現了大名鼎鼎的HashMap,他放棄了線程安全,但是解決了效率問題,我們可以在局部方法和不用考慮線程是否安全的情況下,使用它。但是線程不安全還是有很大風險,這個問題還得需要解決。多說一點HashMap默認長度爲16,還有一個屬性叫做填充比例,默認爲0.75。如果長度超過了長度*填充比例,那麼就得需要擴容了,擴容長度爲原來的兩倍。
於是便創造出來了ConcurrentHashMap,他是線程安全性和效率最好的一個平衡,多併發情況優先考慮。
回到寫這個博文,最開始的問題LinkedHashMap與TreeMap都是可以保證插入數據順序的。LinkedHashMap對於插入刪除數據的速度快,TreeMap的優勢則在於查找數據的時候,底層爲紅黑樹實現,可以根據業務需求使用不同的數據集合。
以下是Map集合總結的表格
Map集合類 | Key | Value | Super | JDK | 說明 |
---|---|---|---|---|---|
HashTable | 不允許爲空 | 不允許爲空 | AbstractMap | 1.0 | 線程安全(過時) |
ConcurrentHashMap | 不允許爲空 | 不允許爲空 | AbstractMap | 1.5 | 鎖分段技術或CAS |
TreeMap | 不允許爲空 | 允許爲空 | AbstractMap | 1.2 | 線程不安全有序 |
HashMap | 允許爲空 | 允許爲空 | AbstractMap | 1.2 | 線程不安全(高併發存在思索問題) |
總結
最後以一個具體的表格進行總結
集合類型 | 描述 |
---|---|
ArrayList | 一種可以動態增長和縮減的索引序列 |
LinkedList | 一種可以在任何位置進行高效的插入和刪除操作的有序序列 |
ArrayDeque | 一種用循環屬豬實現的雙端隊列 |
HashSet | 一種沒有重複元素的無序集合 |
TreeSet | 一種有序集 |
EnumSet | 一種包含枚舉類型的值 |
LinkedHashSet | 一種可以記住插入次序的集合 |
PriorityQueue | 一種允許高效刪除最小元素的集合 |
HashMap | 一種存儲鍵/值關聯的數據結構 |
TreeMap | 一種鍵值有序排列的映射表 |
EnumMap | 一種鍵值屬於枚舉的映射表 |
LinkedHashMap | 一種可以記住插入次序的映射表 |
WeakHashMap | 一種如果值沒有用的情況下被GC的映射表 |
IdentityHashMap | 一種用==而不是用equals比較鍵值的映射表 |