【Java集合】JDK1.7和1.8 HashMap有什么區別


JDK1.7和1.8 HashMap區別:

  1.數組+鏈表改成了數組+鏈表或紅黑樹;

  2.表的插入方式從頭插法改成了尾插法,簡單說就是插入時,如果數組位置上已經有元素,1.7將新元素放到數組中,原始節點作為新節點的后繼節點,1.8遍歷鏈表,將元素放置到鏈表的最后;

  3.在插入時,1.7先判斷是否需要擴容,再插入,1.8先進行插入,插入完成再判斷是否需要擴容

  4.擴容的時候1.7需要對原數組中的元素進行重新hash定位在新數組的位置,1.8采用更簡單的判斷邏輯,位置不變或索引+舊容量大小;

 

原因:

   1.防止發生hash沖突,鏈表長度過長,將時間復雜度由O(n)降為O(logn);

   2.因為1.7頭插法擴容時,頭插法會使鏈表發生反轉,多線程環境下會產生環;

A線程在插入節點B,B線程也在插入,遇到容量不夠開始擴容,重新hash,放置元素,采用頭插法,后遍歷到的B節點放入了頭部,這樣形成了環,如下圖所示:

    

 

 

     1.7的擴容調用transfer代碼,如下所示:

void transfer(Entry[] newTable, boolean rehash) {
  int newCapacity = newTable.length;
  for (Entry<K,V> e : table) {
    while(null != e) {
      Entry<K,V> next = e.next;
      if (rehash) {
        e.hash = null == e.key ? 0 : hash(e.key);
      }
      int i = indexFor(e.hash, newCapacity);
      e.next = newTable[i]; //A線程如果執行到這一行掛起,B線程開始進行擴容
      newTable[i] = e;
      e = next;
    }
  }
}

 

    3.擴容的時候為什么1.8 不用重新hash就可以直接定位原節點在新數據的位置呢?

這是由於擴容是擴大為原數組大小的2倍,用於計算數組位置的掩碼僅僅只是高位多了一個1,怎么理解呢?

擴容前長度為16,用於計算(n-1) & hash 的二進制n-1為0000 1111,擴容為32后的二進制就高位多了1,為0001 1111。

因為是& 運算,1和任何數 & 都是它本身,那就分二種情況,如下圖:原數據hashcode高位第4位為0和高位為1的情況;

第四位高位為0,重新hash數值不變,第四位為1,重新hash數值比原來大16(舊數組的容量)

 

 參考博客:

  https://blog.csdn.net/zhengwangzw/article/details/104889549?depth_1-utm_source=distribute.pc_category.none-task&request_id=&utm_source=distribute.pc_category.none-task


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM