HashMap總結

  1. 默認table數組大小爲16,默認loadFactor=0.75,threshold=數組長度*loadFactor,所以默認爲12。

  2. 當集合中元素當size > threshold時進行resize,數組擴充爲原來當2倍。

  3. 當table數組當長度大於等於64時,衝突元素的的鏈表元素數量大於等於8時鏈表將被一顆紅黑樹取代。

  4. 數組index計算

index=(n - 1) & hash,n爲數組長度,因爲數組的長度總是2的n次方,所以n-1轉換爲二進制低位全部是1,這樣再跟hash與運算,那麼得出的index就更加取決於元素本身而不是數組的長度。

  1. 插入邏輯:

  1. 獲取hashcode。

  2. 計算出hash。

  3. 計算table index,index=(n - 1) & hash,n爲table長度。

  4. 判斷table[index]是否爲null,如果是直接將此節點放入table[index]。

  5. 否則判斷table[index]是否爲TreeNode如果是直接調用方法putTreeVal()將元素插入樹上。

  6. 否則連接到鏈表的末尾。如果鏈表上存在元素其key和將要插入的元素的key相等的,則使用新的value替換老的value。

  7. 當table數組當長度大於等於64時,衝突元素的的鏈表元素數量大於等於8時鏈表將被一顆紅黑樹取代。當不大於64時進行resize操作。

  1. key的相等比較

如果有元素p滿足:
p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))
則說明key已存在,和數組上元素以及鏈表中對元素的比較都是這種比較規則。

對於鏈表,如果hash相同但是key不相等則直接鏈接到鏈表上。

對於紅黑樹,如果hash相同但是key不相等則按照如下順序比較出大小:

  1. 如果實現了Comparable接口則使用compareTo()方法比較大小。

  2. 比較字符串表示的類名大小同樣使用compareTo()比較。

  3. 調用System.identityHashCode()方法生成hashcode比較大小,如下:
    d = (System.identityHashCode(a) <= System.identityHashCode(b) ?-1 : 1),此時一定可以比較出大小

也就是說當衝突元素當hash相等key卻不同時一定要分出個大小。

  1. jdk7中HashMap併發問題。

死鏈問題,擴容時數據丟失,元素被覆蓋。 死鏈問題主要發生在transfer()方法:

void transfer(Entry[] newTable) {
   Entry[] src = table; 
   int newCapacity = newTable.length;   for (int j = 0; j < src.length; j++) { 
       Entry<K, V> e = src[j];       if (e != null) {
           src[j] = null;  
           do {
               Entry<K, V> next = e.next;
               int i = indexFor(e.hash, newCapacity); 
               e.next = newTable[i]; // 1
               newTable[i] = e;      // 2
               e = next;            
           } while (e != null);
       }
   }
}

併發問題主要出現在1、2兩行代碼,這兩行代碼在併發時會互相覆蓋導致死鏈問題。主要是因爲併發修改了共享變量的next屬性。
例如:數組的index=0處有個鏈表,分別是1和2,1的next是2,兩個線程同時resize時,do while循環時,第一次正常,第二次時,第一個線程已經把兩個關係設置成了2元素的next指向1,此時對於線程2:e指向2元素,next指向1元素。第二個線程,第三次循環,e指向了1元素,此時執行e.next = newTable[i],則爲2元素,那麼就形成了1元素的next指向2元素,2元素的next指向1元素,形成環,線程2就會一直運行下去。

  1. LinkedHashMap

LinkedHashMap遍歷的時候保持了出入的順序。其實現原理爲:LinkedHashMap首先繼承了HashMap,其次其內部Entry繼承了HashMap.Node並多了兩個屬性Entry<K,V> before, after;就是這兩個屬性使LinkedHashMap內所有接單連成了一個雙向鏈表,所以也就有了順序性。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章