關於Java集合的部分複習知識點整理
ArrayList
- ArrayList本質上繼承了AbstractList,而AbstractList則是繼承了Collection集合類,而且Arraylist是實現了List的接口
- ArrayList初始的容量,DEFAULT_CAPACITY = 10,即初始容量爲10,但初始化對象的時候能夠傳入你自定義的容量最大容量爲Interger.MaxValue-8
- ArrayList的默認元素存儲,是一個Object[]數組
- ArrayList源碼裏面存在一個ensureCapacity的方法,用來確認數組的容量是否須要擴容,擴容的時候採用的是Arrays.Copyof的方法,複製元素到一個新的數組
- 關於ArrayList的擴容機制,達到了定義容量(不傳入容量的話,即爲默認容量)的時候,會動態擴容1.5倍,也是採用上述的複製方法
- ArrayList實際上是存在手動縮容的方法的,在源碼中有叫作 trimToSize()的方法,通常是手動調用的
- ArrayList中刪除元素的Remove方法其實也是採用arraycopy()的方法來進行元素的移動,本質跟數組差很少
- ArrayList是線程不安全的,裏面沒有實現線程安全的保障,多線程在訪問的時候,實現的自動擴容也是形成線程不安全的一部分緣由。相反,常見的Vector基本上是靠synchronized來實現線程安全的
HashMap
- HashMap實現了Map接口,初始容量爲16,最大容量爲1 << 30,默認加載因子爲0.75,若是本身傳入初始值K,則容量爲大於K的2次方整數,例如:傳入10的話,則容量爲16
![](http://static.javashuo.com/static/loading.gif)
- HashMap的插入原理
![](http://static.javashuo.com/static/loading.gif)
在JDK1.8以前,HashMap使用數組+鏈表實現,即便用鏈表處理衝突,同一hash值的節點都存儲在一個鏈表裏。可是當位於一個桶中的元素較多,即hash值相等的元素較多時,經過key值依次查找的效率較低。而JDK1.8中,HashMap採用數組+鏈表+紅黑樹實現,當鏈表長度超過閾值(8)時,將鏈表轉換爲紅黑樹,這樣大大減小了查找時間,紅黑樹轉鏈表的閾值是6數組
- hash函數是經過拿到key的hashcode,而後讓hashcode的高16位和低16位進行異或操做,這樣設計的緣由是儘量地減少hash碰撞,其二是位運算比較高效
hashmap若是採用頭插法的話,在多線程的狀況下會產生環,而且hashmap在多線程下也是不安全的,在JDK8以前的話,是先判斷擴容再插入的,而JDK8以後則是先插入再判斷是否須要擴容,擴容爲擴容到原數組大小的2倍安全
- 擴容的時候1.7須要對原數組中的元素進行從新hash定位在新數組的位置,1.8採用更簡單的判斷邏輯,位置不變或索引+舊容量大小
- 鏈表轉紅黑樹,並非達到8個Node節點的閾值就進行轉換,而是要判斷一下整個數據結構中的Node數量是否大於64,大於纔會轉,小於就會用擴容數組的方式代替紅黑樹的轉換
擴展
Java中有HashTable、Collections.synchronizedMap、以及ConcurrentHashMap能夠實現線程安全的Map。數據結構
- HashTable是直接在操做方法上加synchronized關鍵字,鎖住整個數組,粒度比較大;
- Collections.synchronizedMap是使用Collections集合工具的內部類,經過傳入Map封裝出一個SynchronizedMap對象,內部定義了一個對象鎖,方法內經過對象鎖實現;
- ConcurrentHashMap使用分段鎖,下降了鎖粒度,讓併發度大大提升。