HashMap常見問題

1. hashMap如何計算key的hash值?爲什麼?

hash = (h=key.hashCode()) ^ (h >>> 16)

因爲在計算下標值的時候,採用的公式如下,其中n是table的長度。

index = (n-1) & hash

計算index的時候,都是取hash值的低n位,高位無法參與運算。爲了降低hash碰撞的概率,取高16位和低16位異或的結果作爲新的低16位,這樣低16位中融合了高16位的特徵,這又稱爲擾動函數

2. 爲什麼hashMap的table長度都是2的n次冪?

  • 和下標值的計算公式有關。方便進行&運算,提高效率,&比取模運算的效率高
       index = (n-1) & hash

table的長度是2的n次冪,纔可以使用上面的公式計算下標值。因爲n-1的二進制的低n位是“低位掩碼”(都是1),使得hash的低n位都可以參與到index的計算中來。
舉例說明,假如讓n=14,那麼n-1(13)的二進制表示就是1101,index的末尾第二位永遠不會等於1。也就是說末尾第二位是1的index,永遠不會被命中。

  • 和擴容過程中Node的遷移有關。令table長度是2的n次冪,則只需要觀察更高一位是0還是1。若是0,則新的下標值等於舊的下標值,若是1,則新的下標值等於舊的下標值加table舊的長度。

3. hashMap初始值如何給定?

預計要存入的數量 / 負載因子 + 1

4. hashMap 與 hashTable 有什麼區別?

  • hashMap線程不安全,效率比較高;hashTable線程安全(syncronized),效率低
  • hashMap的key和value都可以爲空,hashTable都不能爲空

5. hashMap線程安全嗎?爲什麼?

hashMap不是線程安全的。
推薦一篇好文,值得細細品。深入解讀HashMap線程安全性問題
文中大概提及了三個不安全的因素:

  • 併發put導致數據丟失。
  • resize的時候get到null。
  • jdk1.7擴容時形成循環鏈表(1.8已經解決)
    因爲1.7中鏈表採用頭插法,第一個線程中A->B, 第二個線程中把數據遷移到新的table,變成了B->A,之後第一個線程又會把A.next指向B,這樣就形成了循環鏈表。jdk1.8中採用尾插法,解決了此問題
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章