1. 程式人生 > >java Collection介面和Map介面知識點總結

java Collection介面和Map介面知識點總結

        最近寫程式碼,感覺對jdk中Collection和Map中的實現方式和原理有些遺忘,為了在寫程式碼的時候讓程式碼更加簡介和讓效能更加優秀,所以我先必須瞭解其中容器增長方式和原理,HashMap,如果那個Node桶存放的資料大小大於等於8,就會採用紅黑樹儲存。

工具:starUML、IDEA

jdk版本:jdk1.8.0_102

(一)  先貼上一張類圖:

辛苦製作的UML類圖

(二) 其中Collection和Map部分實現中實現引數。

1、 全域性實現的引數:

新容量大小/原容器大小 = N/O

 x = 沒有該值

(一)
Collection
List Set
ArrayList AttributeList RoleList LinkedList Vector Stack HashSet TreeSet LinkedHashSet
實現方式

Object[]

陣列

Object[]

陣列

Object[]

陣列

Node<E>

雙向連結串列

Object[]

陣列

Object[]

陣列

HashMap<E,Object>

NavigableMap<E, Object> HashMap<E,Object>
預設容器大小 10 10 10 x 10 10 16 x 16
擴充容量方式 System.arraycopy System.arraycopy System.arraycopy x System.arraycopy System.arraycopy (Node<K, V>[])new Node[newCap] x (Node<K, V>[])new Node[newCap]
N/O 1.5 1.5 1.5 x 2(預設,值在初始化的第二個引數可設定) 2預設,值在初始化的第二個引數可設定) 2 x 2
負載因子 1 1 1 x 1 1 0.75f x 0.75f
預設門閥 記載因子*容量大小 記載因子*容量大小 記載因子*容量大小 x 記載因子*容量大小 記載因子*容量大小

如果使用無參構造方式,預設門閥為“預設載入因子”*"預設cap大小".

如果使用其他建構函式,門閥值初始為

將該初始因子-1的值寫成機器碼,從最高位(從左往右除符號位的第一個1)開始,右邊所有位變1的值。

x

如果使用無參構造方式,預設門閥為“預設載入因子”*"預設cap大小".

如果使用其他建構函式,門閥值初始為

將該初始因子-1的值寫成機器碼,從最高位(從左往右除符號位的第一個1)開始,右邊所有位變1的值。

執行緒安全 x
(二)
Map
HashMap LinkedHashMap Hashtable WeakHashMap TreeMap EnumMap Attributes ConcurrentHashMap Properties
實現方式

Node<K, V>[]

(根據key的hash值和長度來決定選擇那個桶index)有hashValue,next的連結串列結構(這裡面定義了TreeNode extend LinkedHashMap.Entry)

LinkedHashMap.Entry<K, V> 雙向連結串列實體,繼承HashMap.Node<K, V>

Entry<K,V>[]

是HashMap的安全實現

Entry<K,V>[]

是繼承WeakReference實現弱引用,減少在記憶體中存活時間,節省記憶體。

Entry<K, V>

有right,left,parent的map結構

Object []

陣列

Map<Object, Object>,使用的HashMap實現

Node<K,V>[]

陣列

Entry<K,V>[]

是HashMap的安全實現,是繼承於HashTable

預設容器大小 16 x 11 16 x 動態 11 16 11
擴充容量方式 (Node<K, V>[])new Node[newCap] x new Entry<?, ?>[newCapacity] (Node<K, V>[])new Node<?, ?>[newCap] x x (Node<K, V>[])new Node[newCap] (Node<K, V>[])new Node<?, ?>[n << 1] new Entry<?, ?>[n]
N/O 2 x 2  另外加1 2 x x 2 2 2 另外加1
負載因子 0.75f x 0.75f 0.75f x x 0.75f 0.75f 0.75f
預設門閥

如果使用無參構造方式,預設門閥為“預設載入因子”*"預設cap大小".

如果使用其他建構函式,門閥值初始為

將該初始因子-1的值寫成機器碼,從最高位(從左往右除符號位的第一個1)開始,右邊所有位變1的值。

x 記載因子*容量大小 記載因子*容量大小 x x

如果使用其他建構函式,門閥值初始為

將該初始因子-1的值寫成機器碼,從最高位(從左往右除符號位的第一個1)開始,右邊所有位變1的值。

如果使用其他建構函式,門閥值初始為

將該初始因子-1的值寫成機器碼,從最高位(從左往右除符號位的第一個1)開始,右邊所有位變1的值。

記載因子*容量大小
執行緒安全

2、執行緒安全建構函式和門閥與N/O的關係詳細說明: 

新容量大小/原容器大小 = N/O

新門閥/老門閥 = NT/OT

 x = 不存在

  i = 輸入值

oldCap = 老容器大小

oldCap/2(取整) = oldCap >> 1 

{2^n}=  滿足2的n次方值大於i條件2的n次方的最小值

動態 = 表示它沒有實現,需要傳入一個實現的物件,按照物件來使用

1) 執行緒安全:

執行緒安全(一)
Vector Stack(繼承與Vector)
初始容量 負載因子 門閥 N/O NT/OT 初始容量 負載因子 門閥 N/O NT/OT
預設容器大小 10 x x 2 x 10 x x 2 x
只有initialCapacity引數值 i x x 2 x x x x x x
有initialCapacity,loadFactor引數的值 i x x 這兒沒有loadFactor引數,有capacityIncrement引數,每次增加capacityIncrement x x x x x x
執行緒安全(二)
Stack(繼承與Vector) Hashtable ConcurrentHashMap Properties
NT/OT 初始容量 負載因子 門閥 N/O NT/OT 初始容量 負載因子 門閥 N/O NT/OT 初始容量 負載因子 門閥 N/O NT/OT
預設容器大小 x 11 0.75f 8 2 倍另外單獨+1 2 16 0.75f x 2 2 11 0.75f 8 2 倍另外單獨+1 2
只有initialCapacity引數值 x i 0.75f

i

* 0.75f

2 倍另外單獨+1 2 3i/2 + 1 0.75f

i

* 0.75f

2 2 i 0.75f

i

* 0.75f

2 倍另外單獨+1 2
有initialCapacity,loadFactor引數的值 x i i i(容量) *i(負載因子) 2 倍另外單獨+1 2 {2^i/loadFactor} i i(容量) *i(負載因子) 2 2 i i i(容量) *i(負載因子) 2 倍另外單獨+1 2

2)執行緒不安全:

執行緒不安全(一)
ArrayList AttributeList RoleList LinkedList
初始容量 負載因子 門閥 N/O NT/OT 初始容量 負載因子 門閥 N/O NT/OT 初始容量 負載因子 門閥 N/O NT/OT 初始容量 負載因子 門閥 N/O NT/OT
無參建構函式容器大小 10 x oldCap 1.5 x 10 x oldCap 1.5 x 10 x oldCap 1.5 x x x x x x
只有initialCapacity引數值 i x oldCap 1.5 x i x oldCap 1.5 x i x oldCap 1.5 x x x x x x
有initialCapacity,loadFactor引數的值 i x oldCap 1.5 x i x oldCap 1.5 x i x oldCap 1.5 x x x x x x
執行緒不安全(二)
HashSet(資料儲存是通過HashMap實現的) TreeSet LinkedHashSet(繼承HashSet) HashMap
初始容量 負載因子 門閥 N/O NT/OT 初始容量 負載因子 門閥 N/O NT/OT 初始容量 負載因子 門閥 N/O NT/OT 初始容量 負載因子 門閥 N/O NT/OT
無參建構函式容器大小 16 0.75f 12 2 2 x x x x x 16 0.75f 12 2 2 16 0.75f 12 2 2
只有initialCapacity引數值 {2^n} 0.75f

{2^n}

* 0.75f

2 2 x x x x x {2^n} 0.75f

{2^n}

* 0.75f

2 2 {2^n} 0.75f

{2^n}

* 0.75f

2 2
有initialCapacity,loadFactor引數的值 {2^n} i

{2^n}

* 0.75f

2 2 x x x x x {2^n} i

{2^n}

* 0.75f

2 2 {2^n} i

{2^n}

* 0.75f

2 2
執行緒不安全(三)
LinkedHashMap WeakHashMap TreeMap EnumMap Attributes(資料用HashMap來儲存)
初始容量 負載因子 門閥 N/O NT/OT 初始容量 負載因子 門閥 N/O NT/OT 初始容量 負載因子 門閥 N/O NT/OT 初始容量 負載因子 門閥 N/O NT/OT 初始容量 負載因子 門閥 N/O NT/OT
16 0.75f 12 2 2 16 0.75f 12 2 2 x x x x x 動態 動態 動態 動態 動態 16 0.75f

{2^n}

* 0.75f

2 2
i 0.75f

{2^n}

* 0.75f

2 2 {2^n} 0.75f

{2^n}

* 0.75f

2 2 x x x x x 動態 動態 動態 動態 動態 {2^n} 0.75f

{2^n}

* 0.75f

2 2
i i

{2^n}

* 0.75f

2 2 {2^n} i

{2^n}

* 0.75f

2 2 x x x x x 動態 動態 動態 動態 動態 x x x x

 補充描述:這裡面有些很複雜,詳細還是得去研究原始碼,而且,每個jdk版本的實現的方式不一樣,建議有時間詳細看原始碼,瞭解其中原理。最重要的是HashMap,TreeMap,Hashtable,ConcurrentHashMap這些詳細檢視很有用, 這個其中還常使用到CAS。

(三) 知識點總結:

HashMap,雖然儲存資料是通過key-value的形式儲存的,但是,它內部為了提高查詢效率,使用的key的hash值,構建陣列物件鏈。先是陣列,稱作“桶”,通過hash值來判斷放那個桶,桶的數量就是上面的cap。每個桶存放的資料小於8個的時候,是採用簡單的物件表,如果那個Node桶存放的資料大小大於等於8,針對該桶的資料就會採用紅黑樹儲存。

ConcurrentHashMap在這個版本實現和HashMap內容差不多,只是增加了執行緒安全的操作,其中載入因子只是在容器初始化的時候和cap通過cap/loadFactor + 1向上取2^n的整數,還有這個版本Segment只有在JAVA物件流進行序列化和反序列化中使用。