1. 程式人生 > >Java基礎加強之集合

Java基礎加強之集合

依然 部分 t對象 方法返回值 需要 不可 img 技術分享 jdk

集合整體框架圖

技術分享圖片

各集合框架的概述

1. Collection(常用List和Set,不常用Queue和Vector),單元素集合。

2. Map(常用HashMap和TreeMap,不常用HashTable),key-value映射關系。

3. Iterator(叠代器)

4. Comparable和Comparator比較器

5. Collections和Arrays工具類

Java中結合和數組的比較

1. 數組的長度在初始化時指定,只能保存定長的數據。

  而集合可以保存不確定長度的數據。同時可以保存具有映射關系的數據(即關聯數組,鍵值對key-value)。

2. 數據元素既可以是基本類型的值,也可以是對象,集合只能保存對象

(實際上是只保存對象的引用變量),基本數據類型的變量要轉換成對應的包裝類才能放入集合中。

常用集合特性概述

List系

List的特點:元素有放入順序,元素可以重復

List接口的三個實現類:ArrayList、LinkedList和Vector。

ArrayList、LinkedList和Vector的區別

LinkedList:底層是基於鏈表實現,鏈表內存是散亂的,每一個元素存儲本身內存地址的同時也存儲下一個元素的內存地址。鏈表增刪快,查找慢。

ArrayList和Vector:兩者底層都是基於數組實現的,查詢快,增刪慢。兩者之間的區別是ArrayList是線程非安全的,效率高;而Vector是線程安全的,效率低。

ArrayList的初始化大小是10,擴容策略是1.5倍原元素數量的大小。

選擇標準

如果涉及到“動態數組”、“棧”、“隊列”、“鏈表”等結構,應該考慮用List,具體選擇哪個List實現類,根據下面的標準來取舍:

1. 對於需要快速插入、刪除元素,應該使用LinkedList。

2. 對於需要快速隨機訪問元素,應該使用ArrayList。

3. 對於“單線程環境”或者“多線程環境,但List僅僅只會被單個線程操作”,此時應該使用非同步的類(如ArrayList)。對於“多線程環境,且List可能同時被多個線程操作”,此時,應該使用同步的類(如Vector)。

Set系

Set的特點:元素放入無順序,元素不可重復。

Set接口的三個實現類:LinkedSet、HashSet和LinkedHashSet。

HashSet(底層是通過HashMap實現)底層通過HashCode和equals去重。

HashSet中判斷集合元素相等

兩個對象比較 具體分為如下四個情況:
1.如果有兩個元素通過equal()方法比較返回false,且它們的hashCode()方法返回不相等,HashSet將會把它們存儲在不同的位置。

2.如果有兩個元素通過equal()方法比較返回true,但它們的hashCode()方法返回不相等,HashSet將會把它們存儲在不同的位置。

3.如果兩個對象通過equals()方法比較不相等,但hashCode()方法比較相等,HashSet將會把它們存儲在相同的位置,在這個位置以鏈表式結構來保存多個對象。這是因為當向HashSet集合中存入一個元素時,HashSet會調用對象的hashCode()方法來得到對象的hashCode值,然後根據該hashCode值來決定該對象存儲在HashSet中存儲位置。

4.如果有兩個元素通過equal()方法比較返回true,且它們的hashCode()方法返回true,HashSet將不予添加。

HashSet判斷兩個元素相等的標準:兩個對象通過equals()方法比較相等,並且兩個對象的hashCode()方法返回值也相等。

註意:HashSet是根據元素的hashCode值來快速定位的,如果HashSet中兩個以上的元素具有相同的hashCode值,將會導致性能下降。所以如果重寫類的equals()方法和hashCode()方法時,應盡量保證兩個對象通過hashCode()方法返回值相等時,通過equals()方法比較返回true。

LinkedHashSet類

LinkedHashSet是HashSet對的子類,也是根據元素的hashCode值來決定元素的存儲位置,同時使用鏈表維護元素的次序,使得元素是以插入的順序來保存的。當遍歷LinkedHashSet集合裏的元素時,LinkedHashSet將會按元素的添加順序來訪問集合裏的元素。但是由於要維護元素的插入順序,在性能上略低與HashSet,但在叠代訪問Set裏的全部元素時有很好的性能。
註意:LinkedHashSet依然不允許元素重復,判斷重復標準與HashSet一致。

補充:HashSet的實質是一個HashMap。HashSet的所有集合元素,構成了HashMap的key,其value為一個靜態Object對象因此HashSet的所有性質,HashMap的key所構成的集合都具備。可以參考後續文章中HashMap的相關內容進行比對。

TreeSet類

TreeSet是SortedSet接口的實現類,正如SortedSet名字所暗示的,TreeSet可以確保集合元素處於排序狀態。此外,TreeSet還提供了幾個額外的方法。

1 comparator():返回對此 set 中的元素進行排序的比較器;如果此 set 使用其元素的自然順序,則返回null。
2 first():返回此 set 中當前第一個(最低)元素。
3 last(): 返回此 set 中當前最後一個(最高)元素。
4 lower(E e):返回此 set 中嚴格小於給定元素的最大元素;如果不存在這樣的元素,則返回 null5 higher(E e):返回此 set 中嚴格大於給定元素的最小元素;如果不存在這樣的元素,則返回 null6 subSet(E fromElement, E toElement):返回此 set 的部分視圖,其元素從 fromElement(包括)到 toElement(不包括)。
7 headSet(E toElement):返回此 set 的部分視圖,其元素小於toElement。
8 tailSet(E fromElement):返回此 set 的部分視圖,其元素大於等於 fromElement。

Map系

Map的特點:存儲的元素是鍵值對,在JDK1.8版本中是Node,在老版本中是Entry。

Map接口有四個實現類:HashMap、HashTable、LinkedHashMap和ConcurrentHashMap。

HashMap類

HashMap是非線程安全,高效,支持null的key和value,底層實現是數組和鏈表,通過HashCode方法和equals方法保證鍵的唯一性。

如果需要使用線程安全的Map可以有兩種方式:

1. 采用HashTable

2. 采用Collections.synchronizedMap(hashMap)方式進行同步。

解決沖突主要有三種方法:定址法、拉鏈發和再散列發。

HashMap是采用拉鏈法解決哈希沖突的,拉鏈法是將相同hash值的對象組成一個鏈表放在hash值對應的槽位。

HashMap的初始化大小是16,擴展因子是0.75,擴容策略是2倍原容量的大小。

put的大致流程

1. 通過hashCode方法計算出key的hash值

2. 通過hash%length計算出存儲在table中的index(源碼中是使用hash&(length-1),這樣結果相同,但是更快)。

3. 如果此時table[index]的值為空,那麽就直接存儲,如果不為空那麽就鏈接到這個數所在的鏈表的頭部。(在JDK1.8中,如果鏈表長度大於8就轉化成紅黑樹)

get的大致流程

1. 通過通過hashCode方法計算出key的hash值

2. 通過hash%length計算出存儲在table中的index(源碼中是使用hash&(length-1),這樣結果相同,但是更快)。

3. 遍歷table[index]所在的鏈表,只有當key與該節點中的key的值相同時才取出。

ConcurrentHashMap類

是從JDK1.5之後提供的一個HashTable的替代實現,采用分段鎖機制,一個map中的元素分成很多的segment,通過lock機制可以對每個segment加讀寫鎖,從而提高map的效率,底層實現采用數組+鏈表+紅黑樹的存儲結構。

HashTable類

線程安全,低效,不支持null的key和value。

SortedMap類

有一個實現類:TreeMap會存儲放入元素的順序。

Java基礎加強之集合