Java集合类梳理
文章目錄
- 集合框架
- Collection
- List
- List常用方法
- ArrayList
- ArrayList常用方法
- LinkedList
- LinkedList常用方法
- Vector
- Vector 常用方法
- Stack
- Stack 常用方法
- Set
- HashSet
- HashSet 常用方法
- LinkedHashSet
- LinkedHashSet 常用方法
- TreeSet
- TreeSet常用方法
- EnumSet
- EnumSet 常用方法
- Map
- HashMap
- HashMap 常用方法
- Hashtable
- LinkedHashMap
- LinkedHashMap 的常用方法
- TreeMap
- TreeMap 常用方法
- TreeMap 排序方式
- WeakHashMap
- WeakHashMap 常用方法
- IdentityHashMap
- IdentityHashMap 常用方法
- EnumMap
- EnumMap 常用方法
- Properties
- Properties 常用方法
集合框架
Collection
Collection 接口用于表示任何對象或元素組。它是 List 和 Set 的父接口。
Collection 聲明的方法:
點擊查看方法摘要
List
List集合代表一個有序、可變長、可重復的集合,集合中每個元素都有其對應的順序索引。List集合默認按照元素的添加順序設置元素的索引,可以通過索引(類似數組的下標)來訪問指定位置的集合元素。
List相當于下圖的格子,按順序放入值,for循環可以挨個取出:
實現List接口的集合主要有:ArrayList、LinkedList、Vector、Stack。
特點梳理:
-
List集合為列表類型,以線性方式,有序存取對象。各元素的順序就是對象插入時的順序,即元素按進入先后有序保存。
-
List集合有序是指存儲的元素有下標,下標從0開始,以1遞增。所以可以通過使用索引來訪問List集合中的元素,即可以用下標進行元素的操作
-
List集合中的元素允許重復,即可以存儲重復的元素。
List常用方法
點擊查看方法摘要
ArrayList
ArrayList是一個動態數組,也是我們最常用的集合,是List類的典型實現。它允許任何符合規則的元素插入甚至包括null。每一個ArrayList都有一個初始容量(10),該容量代表了數組的大小。隨著容器中的元素不斷增加,容器的大小也會隨著增加。在每次向容器中增加元素的同時都會進行容量檢查,當快溢出時,就會進行擴容操作。所以如果我們明確所插入元素的多少,最好指定一個初始容量值,避免過多的進行擴容操作而浪費時間、效率。
如上圖,ArrayList若要找Killer,則要通過for循環,從Tom開始挨個找才能找到,ArrayList的查詢速度比LinkedList快,但不及HashMap快。數據若是很龐大,而且又頻繁查找的業務,建議使用散列表。
特點梳理:
-
底層數據結構是數組,添加、查找、刪除均采用基本數組操作,可以存儲重復元素
-
查找效率高,添加、刪除效率低,整體效率高
-
初始大小10,最大容量Integer.MAX_VALUE - 8
-
滿時擴容,擴容大小為1.5倍,(int newCapacity = oldCapacity + (oldCapacity >> 1)。
-
采用Arrays.copyOf()產生新數組
-
沒有同步,線程不安全
ArrayList常用方法
點擊查看方法摘要
LinkedList
LinkedList 是List 接口的另一個實現類,除了可以根據索引訪問集合元素外,LinkedList 還實現了 Deque 接口,可以當作雙端隊列來使用,也就是說,既可以當作“棧”使用,又可以當作隊列使用。
LinkedList 的實現機制與 ArrayList 的實現機制完全不同,ArrayList 內部以數組的形式保存集合的元素,所以隨機訪問集合元素有較好的性能;LinkedList 內部以鏈表的形式保存集合中的元素,所以隨機訪問集合中的元素性能較差,但在插入刪除元素時有較好的性能。
特點梳理:
-
同時實現了Queue和Deque接口
-
底層采用雙向鏈表實現,頭結點不存放數據,允許為null
-
只要是遍歷鏈表就需要使用 ListIterator
-
索引優化,可以根據 index 可以選擇從 first 和 last 開始遍歷
-
線程不安全
LinkedList常用方法
點擊查看方法摘要
Vector
與 ArrayList 相似,但是 Vector 是同步的。所以說 Vector 是線程安全的動態數組。它的操作與 ArrayList 幾乎一樣。
Vector 類實現了可擴展的對象數組。 像數組一樣,它包含可以使用整數索引訪問的組件。 但是, Vector 的大小可以根據需要增長或縮小,以適應在創建 Vector 之后添加和刪除項目。
特點梳理:
-
底層由數組實現,添加、查找、刪除均采用基本數組操作,所以查找效率高,添加、刪除效率低
-
初始大小10,最大容量 Integer.MAX_VALUE - 8
-
滿時擴容,擴容大小為1.5倍,(int newCapacity = oldCapacity + (oldCapacity >> 1)
-
采用 Arrays.copyOf() 產生新數組
-
線程不安全
Vector 常用方法
點擊查看方法摘要
Stack
Stack 繼承自 Vector,實現一個后進先出的堆棧。Stack 提供5個額外的方法使得 Vector 得以被當作堆棧使用。基本的 push 和 pop 方法,還有 peek 方法得到棧頂的元素,empty 方法測試堆棧是否為空,search 方法檢測一個元素在堆棧中的位置。Stack 剛創建后是空棧。
Stack 常用方法
點擊查看方法摘要
Set
繼承自 Collection 接口,且方法相同,Set 沒有在 Collection 的基礎上進行功能的擴展,只是比Collection 接口更加嚴格了,Set 接口是無序的。
Set集合的實現類可說是基于Map集合去寫的。通過內部封裝Map集合來實現的比如HashSet內部封裝了HashMap。
Set相當于往袋子里放東西,無序取出(使用迭代器取出),如下圖:
特點梳理:
-
繼承自Collection
-
Set集合中的元素無序,即插入無序
-
不可指定位置訪問,即沒有索引值
HashSet
HashSet是Set集合最常用實現類,是其經典實現。HashSet是按照hash算法來存儲元素的,因此具有很好的存取和查找性能。
HashSet使用HashMap的數據結構,僅使用HashMap中的key結構,value值一律為null。也就是說真實數據存儲在 HashMap 的 key 列,value 列全部為空。
HashSet 存儲原理:
當向 HashSet 集合存儲一個元素時,HashSet 會調用該對象的 hashCode() 方法得到其 hashCode 值,然后根據 hashCode 值決定該對象的存儲位置,
HashSet 集合判斷兩個元素相等的標準是:
因此,如果(1)和(2)有一個不滿足條件,則認為這兩個對象不相等,可以添加成功。如果兩個對象的 hashCode() 方法返回值相等,但是兩個對象通過 equals() 方法比較返回 false,HashSet會以鏈式結構將兩個對象保存在同一位置,這將導致性能下降,因此在編碼時應避免出現這種情況。
HashSet 查找原理:
基于 HashSet 以上的存儲原理,在查找元素時,HashSet 先計算元素的 HashCode 值(也就是調用對象的 hashCode 方法的返回值),然后直接到 hashCode 值對應的位置去取出元素即可,這就是 HashSet 速度很快的原因。
重寫 hashCode() 方法的基本原則:
特點梳理:
-
不能保證元素的順序
-
HashSet不是線程同步的,如果多線程操作HashSet集合,則應通過代碼來保證其同步
-
集合元素值可以是null
HashSet 常用方法
點擊查看方法摘要
LinkedHashSet
LinkedHashSet 是 HashSet 的一個子類,具有 HashSet 的特性,也是根據元素的 hashCode 值來決定元素的存儲位置。但它使用鏈表維護元素的次序,元素的順序與添加順序一致。由于 LinkedHashSet 需要維護元素的插入順序,因此性能略低于 HashSet,但在迭代訪問 Set 里的全部元素時有很好的性能。
LinkedHashSet 是一個非線程安全的集合。如果有多個線程同時訪問當前 LinkedHashSet 集合容器,并且有一個線程對當前容器中的元素做了修改,那么必須要在外部實現同步保證數據的冥等性。
特點梳理:
-
LinkedHashSet的底層使用LinkedHashMap存儲元素
-
LinkedHashSet是有序的,它是按照插入的順序排序的
-
LinkedHashSet 是一個非線程安全的集合
LinkedHashSet 常用方法
點擊查看方法摘要
TreeSet
TreeSet 是 SortedSet 接口的實現類,TreeSet可以保證元素處于排序狀態,它采用紅黑樹的數據結構來存儲集合元素。TreeSet 支持兩種排序方法:自然排序和定制排序,默認采用自然排序。
排序:
當向TreeSet中添加自定義對象時,有 2 種排序方法:
要求自定義類實現 java.lang.Comparable 接口并重寫 compareTo(Object obj) 方法。在此方法中,指明按照自定義類的哪個屬性進行排序
當元素不具備比較性時,此時只能為容器添加比較器來解決問題,即創建 TreeSet 時向其中加入Comparator
特點梳理:
-
有序
-
不可重復
-
紅黑樹
-
基于Treemap實現
-
自定義排序等特點
-
非線程安全
-
TreeSet中存儲的類型必須是一致的,不能一下存 int,一下又存 String
TreeSet常用方法
點擊查看方法摘要
EnumSet
EnumSet 是一個專為枚舉類設計的集合抽象類,EnumSet 中的所有元素都必須是指定枚舉類型的枚舉值,該枚舉類型在創建EnumSet時顯式或隱式地指定。不允許添加 null 值。EnumSet 的集合元素也是有序的,它以枚舉值在 Enum 類內的定義順序來決定集合元素的順序。
特點梳理:
-
EnumSet的集合元素也是有序的,EnumSet以枚舉值在Enum類內的定義順序來決定集合元素的順序
-
EnumSet在內部以位向量的形式存儲,這種存儲形式非常緊湊、高效,因此 EnumSet 對象占用內存很小,而且運行效率很好。尤其是進行批量操作(如調用containsAll()和retainAll()方法)時,如果其參數也是EnumSet集合,則該批量操作的執行速度也非常快
-
EnumSet 集合不允許加入 null 元素,如果試圖插入 null 元素,EnumSet 將拋出 NullPointerException 異常
-
EnumSet 類沒有暴露任何構造器來創建該類的實例,程序應該通過它提供的類方法來創建 EnumSet 對象
-
如果只是想判斷 EnumSet 是否包含 null 元素或試圖刪除 null 元素都不會拋出異常,只是刪除操作將返回false,因為沒有任何 null 元素被刪除。
EnumSet 常用方法
點擊查看方法摘要
Map
Map 接口采用鍵值對 Map<K,V> 的存儲方式,保存具有映射關系的數據,因此,Map 集合里保存兩組值,一組值用于保存 Map 里的 key,另外一組值用于保存 Map 里的 value,key 和 value 可以是任意引用類型的數據。key 值不允許重復,可以為 null。如果添加 key-value 對時 Map 中已經有重復的 key,則新添加的 value 會覆蓋該 key 原來對應的 value。常用實現類有 HashMap、LinkedHashMap、TreeMap等。
Map 聲明的方法:
點擊查看方法摘要
HashMap
HashMap 基于 hashing 原理,通過 put() 和 get() 方法存儲和獲取對象。當我們將鍵值對傳遞給 put() 方法時,它調用鍵(key)對象的 hashCode() 方法來計算 hashCode 值,然后找到對應的 bucket 位置來儲存值(value)對象。當獲取對象時,通過鍵(key)對象的 equals() 方法找到正確的鍵值對,然后返回對象。HashMap使用鏈表來解決碰撞問題,當發生碰撞了,對象將會存儲在鏈表的下一個節點中。
原理圖 1:
注:JDK1.8中,HashMap采用數組+鏈表+紅黑樹實現,當鏈表長度超過閾值(8)時,將鏈表轉換為紅黑樹,這樣大大減少了查找時間。
原理圖 2:
原理圖 3:
如上“原理圖 3”,散列表中有散列數組,散列數組存放的元素是線性表(散列桶)。往散列表存放數據是鍵值對放進去,“Mac”和“Jerry”的HashCode一樣,所以計算出來的散列值一樣,假設該散列值計算得到的下標是2,就將“Mac”和“Jerry”存放在散列數組下標為2的這個散列桶里。而“Andy”的散列值計算得到的下標是8,那么“Andy”就保存在下標為8的散列桶里。由于所存放的數據只在下標為2和8的散列桶中,所以散列數組中其它位置則為空值。要找25這個元素,只要計算“Jerry”的散列值,最后計算得到下標2,然后在對應的散列桶中依次查找“Jerry”,就可以找到對應的25。
其實真正意義上的散列表如下圖所示,以上“原理圖”只是說明原理罷了,使用HashMap時將其想象成多行兩列的表格即可。
真正存取的有意義的元素是key值所對應的value值,key值只不過是value值所取的名字,為了方便以后的查找之用。
特點梳理:
-
底層采用哈希表+鏈表或紅黑樹實現。
-
哈希表初始容量 1<<4,最大容量 1<<30,默認負載因子0.75f。
-
閾值為負載因子*容量,到達閾值時擴容,擴容為兩倍,或者在最開始的時候,這是為了如果預計Hashmap會很大,可以把初始值調大。
-
當一個桶的節點數大小到達 8,開始從鏈表轉換為紅黑樹。當一個紅黑樹大小到達 6,退化為鏈表。
-
線程不安全
HashMap 常用方法
點擊查看方法摘要
Hashtable
HashMap 與 Hashtable 是 Map 接口的兩個典型實現,它們之間的關系完全類似于 ArrayList 與 Vertor。HashTable 是一個古老的 Map 實現類,它提供的方法比較繁瑣,目前基本不用了。
原理圖:
LinkedHashMap
對于 LinkedHashMap 而言,它繼承自 HashMap,底層使用哈希表與雙向鏈表來保存所有元素。其基本操作與父類HashMap相似。LinkedHashMap 使用雙向鏈表來維護 key-value 對的次序(其實只需要考慮 key 的次序即可),該鏈表負責維護 Map 的迭代順序,默認與插入順序一致(默認情況,遍歷時的順序是按照插入節點的順序),即在每次插入數據,或者訪問、修改數據時,會增加節點、或調整鏈表的節點順序,以決定迭代時輸出的順序。
可以在構造時傳入 accessOrder 參數,使得其遍歷順序按照訪問的順序輸出。
原理圖:
特點梳理:
-
繼承自HashMap
-
額外使用類似于LinkedList的雙向鏈表,維護插入順序
-
線程不安全,效率高
-
鍵和值都可以是 null
-
底層由雙向鏈表和哈希表組成
-
鍵元素:唯一(由哈希表結構保證)、有序(按照錄入順序,由鏈表結構保證)
LinkedHashMap 的常用方法
點擊查看方法摘要
TreeMap
TreeMap 是 SortedMap 的實現類,是一個紅黑樹的數據結構,每個 key-value 對作為紅黑樹的一個節點。TreeMap 存儲 key-value 對時,需要根據 key 對節點進行排序。
TreeMap 繼承自 AbstractMap,實現了 Map, Cloneable, NavigableMap, Serializable 接口:
TreeMap 繼承于 AbstractMap,而 AbstractMap 實現了 Map 接口,并實現了 Map 接口中定義的方法,減少了其子類繼承的復雜度
TreeMap 實現了 Map 接口,成為 Map 框架中的一員,可以包含著 key-value 形式的元素
TreeMap 實現了 NavigableMap 接口,意味著擁有了更強的元素搜索能力
TreeMap 實現了 Cloneable 接口,實現了 clone() 方法,可以被克隆
TreeMap 實現了 Java.io.Serializable 接口,支持序列化操作,可通過 Hessian 協議進行傳輸
特點梳理:
-
底層采用紅黑樹實現
-
保存的元素按照一定的規則有序
-
可以傳入比較器,即可自定義排序規則,不然就按照key排序
-
非線程安全
TreeMap 常用方法
點擊查看方法摘要
TreeMap 排序方式
-
自然排序:TreeMap 的所有 key 必須實現 Comparable 接口,而且所有的 key 應該是同一個類的對象,否則會拋出ClassCastException。
-
定制排序:創建TreeMap時,傳入一個Comparator對象,該對象負責對TreeMap中的所有key進行排序。
WeakHashMap
WeakHashMap 繼承于AbstractMap,實現了Map接口。和HashMap一樣,WeakHashMap 也是一個散列表,它存儲的內容也是鍵值對(key-value)映射,而且鍵和值都可以是null。不過WeakHashMap的鍵是“弱鍵”。在 WeakHashMap 中,當某個鍵不再正常使用時,會被從WeakHashMap中被自動移除。更精確地說,對于一個給定的鍵,其映射的存在并不阻止垃圾回收器對該鍵的丟棄,這就使該鍵成為可終止的,被終止,然后被回收。某個鍵被終止時,它對應的鍵值對也就從映射中有效地移除了。
這個“弱鍵”的原理呢?大致上就是,通過WeakReference和ReferenceQueue實現的。 WeakHashMap的key是“弱鍵”,即是WeakReference類型的;ReferenceQueue是一個隊列,它會保存被GC回收的“弱鍵”。實現步驟是:
新建WeakHashMap,將“鍵值對”添加到WeakHashMap中。
實際上,WeakHashMap是通過數組table保存Entry(鍵值對);每一個Entry實際上是一個單向鏈表,即Entry是鍵值對鏈表。
當某“弱鍵”不再被其它對象引用,并被GC回收時。在GC回收該“弱鍵”時,這個“弱鍵”也同時會被添加到ReferenceQueue(queue)隊列中。
當下一次我們需要操作WeakHashMap時,會先同步table和queue。table中保存了全部的鍵值對,而queue中保存被GC回收的鍵值對;同步它們,就是刪除table中被GC回收的鍵值對。
這就是“弱鍵”如何被自動從WeakHashMap中刪除的步驟了。
WeakHashMap 常用方法
點擊查看方法摘要
IdentityHashMap
IdentityHashMap 比較 key 時是“引用相等”,即對于 k1 和 k2,當k1 == k2 時,IdentityHashMap 認為兩個key相等。
IdentityHashMap 允許使用 null 作為 key 和 value.,不保證任何 Key-value 對之間的順序, 更不能保證他們的順序隨時間的推移不會發生變化。
IdentityHashMap 有其特殊用途,比如序列化、深度復制、記錄對象代理等。
IdentityHashMap 常用方法
點擊查看方法摘要
EnumMap
Map 接口的實現,其 key-value 映射中的 key 是 Enum 類型。其原理就是一個對象數組,數組的下標索引就是根據 Map 中的 key 直接獲取,即枚舉中的 ordinal 值。效率比 HashMap 高,可以直接獲取數組下標索引并訪問到元素。
EnumMap 常用方法
點擊查看方法摘要
Properties
Properties 類是 Hashtable 類的子類,它相當于一個 key、value 都是 String 類型的 Map ,主要用于讀取配置文件。
Properties 常用方法
點擊查看方法摘要
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
- 上一篇: 反码、原码、补码的观点阐述
- 下一篇: Java集合类原理详解