一、ArrayList的擴容機制
- 每次擴容是原來容量的1.5倍,經過移位的方法實現。
- 使用copyOf的方式進行擴容。
擴容算法是首先獲取到擴容前容器的大小。而後經過oldCapacity + (oldCapacity >> 1) 來計算擴容後的容器大小newCapacity。這裏用到了>> 右移運算,即容量增大原來的1.5倍。還要注意的是,這裏擴充容量時,用的時Arrays.copyOf方法,其內部也是使用的System.arraycopy方法。
區別:java
- arraycopy()須要目標數組,將原數組拷貝到你本身定義的數組裏,並且能夠選擇拷貝的起點和長度以及放入新數組中的位置。
- copyOf()是系統自動在內部新建一個數組,並返回該數組。
二、數組和ArrayList的區別
- 數組能夠包含基本類型,ArrayList成員只能是對象。
- 數組大小是固定的,ArrayList能夠動態擴容。
三、ArrayList和LinkedList的區別
ArrayList 和 LinkedList 都是不一樣步的,也就是不保證線程安全;算法
LinkedList 是基於雙向鏈表實現的,ArrayList 是基於數組實現的。數組
ArrayList 支持隨機訪問,因此查詢速度更快,LinkedList 添加、插入、刪除元素速度更快。安全
ArrayList的空間浪費主要體如今在list列表的結尾會預留必定的容量空間,LinkedList使用Node來存儲數據每一個Node中不只存儲元素的值,還存儲了前一個 Node 的引用和後一個 Node 的引用,佔用內存更多。數據結構
實現了RandomAccess接口的list,優先選擇普通for循環 ,其次foreach,
未實現RandomAccess接口的list, 優先選擇iterator遍歷(foreach遍歷底層也是經過iterator實現的),大size的數據,千萬不要使用普通for循環。多線程
四、如何建立同步的List
能夠經過Collections.sychronizeList將list轉換成同步list,或者直接使用CopyOnWriteArrayList。併發
五、CopyOnWriteArrayList
- 讀時不加鎖,寫入時加鎖,寫入時建立一個新入組將老數組拷貝進入新數組,並將數據加入新數組。
- 只能保證最終一致性。
六、Vector
ArrayList線程安全的一個版本,底層經過synchronize加鎖實現線程安全。dom
七、HashMap擴容機制
HashMap使用resize()方法來進行擴容,計算table數組的新容量和Node在新數組中的新位置,將舊數組中的值複製到新數組中,從而實現自動擴容。spa
- 當空的HashMap實例添加元素時,會以默認容量16爲table數組的長度擴容,此時 threshold = 16 * 0.75 = 12。
- 當不爲空的HashMap實例添加新元素數組容量不夠時,會以舊容量的2倍進行擴容,固然擴容也是大小限制的,擴容後的新容量要小於等於規定的最大容量,使用新容量建立新table數組,而後就是數組元素Node的複製了,計算Node位置的方法是 index = (n-1) & hash,這樣計算的好處是,Node在新數組中的位置要麼保持不變,要麼是原來位置加上舊數組的容量值,在新數組中的位置都是能夠預期的(有規律的),而且鏈表上Node的順序也不會發生改變。
八、HashMap爲何不是線程安全的
- 沒有鎖操做,兩個線程操做同一個hashMap會出現線程安全的問題,可能會致使數據丟失。
- resize的時候會出現死鎖,覺得hash衝突以後採用鏈地址法解決hash衝突,可是兩個線程都進行擴容的時候,鏈表使用頭插法,致使出現循環引用,出現死鎖。1.8以後 鏈表都是採用尾插法。避免了死循環的問題。
九、爲何HashMap的hashCode要高16位異或hashCode
由於元素所處位置只與低n位相關,高16位與hashcode進行異或是爲了減小碰撞。
異或是二者相同返回0 不相同返回1。線程
十、爲何HashMap的容量要是2的N次冪
- 取模時分配更均勻。
- 擴容成本更低。
2^n下有特性:
x%2^n=x&(2^n-1)
只有2的冪次方纔有此特性。
十一、ConcurrentHashMap的實現
- jdk1.7以前,使用分段鎖來實現,默認支持的併發度爲16,segment繼承自reetrantlock,segment充當鎖角色。每一個segment中包含一個小的hash表。size方法將segment的count相加,計算兩次,若是兩次結果相同,說明計算準確,不然每一個segment從新加鎖計算。
- jdk1.8以後取消分段鎖的設計,採用CAS+Synchronized保證線程安全。主要是鎖住鏈表的頭結點。size方法使用一個volatile變量baseCount記錄元素個數,當插入新數據或者刪除數據的時候會更新baseCount的值。
十二、ConcurrentHashMap1.7與1.8異同
- 1.8取消了分段鎖,鎖的粒度更小,減小併發衝突的機率。
- 1.8採用了鏈表+紅黑樹的實現方式,對查詢的提高很大。
1三、爲何ConcurrentHashMap讀操做不加鎖
- ConcurrentHashMap只保證最終一致性,並不能保證強一致性。
- 對於value使用valitile關鍵字,保證內存可見,可以被多線程同時讀,而且不會讀到過時的值。根據java內存模型的hanpends-befor原則,對volatitle的寫入操做先於讀操做,即便兩個線程同時讀取和寫入同一個變量,也能是get操做拿到最新值
- Node使用volatitle關鍵字標識是爲了數組擴容時的可見性。
1四、LinkedHashMap的實現
基於hashMap和雙向鏈表實現的,線程不安全。
1五、HashSet的實現
- 底層是經過hashMap實現的。
- 判斷兩個對象是否相等,先判斷hashCode是否相等,若是相等再判斷equals,這就是爲何重寫equals方法要重寫hashCode方法。
1六、TreeMap的實現
底層使用紅黑樹實現。根據鍵值進行排序,key必須實現Compareable接口或者構造TreeMap時傳入Comparetor。
1七、TreeSet的實現
底層使用TreeMap實現,即便用紅黑樹進行實現。
Set判斷兩個元素是否相等,先判斷hashCode再使用equals
1八、解決Hash衝突的方法
- 開放定址法
- 鏈地址法
- 再hash法
1九、List、Map、Set存儲的null值
- list null值,加幾個存幾個。
- set null值 只存一個。
- map只存在一個null值對。
20、平衡二叉樹AVL與紅黑樹的區別
- 平衡二叉樹是高度平衡的,每次的插入和刪除,都要進行rebalance操做。
- 紅黑樹不是高度平衡的。
紅黑樹定義:
- 節點是紅色或黑色。
- 根節點是黑色。
- 每條路徑上的黑色節點數目相同。
- 子節點和父節點的顏色不相同。