為什么HashMap擴容是2倍以及容量為什么是2的n次冪


** java8**
為什么HashMap擴容是2倍以及容量為什么是2的n次冪,和這個數組下標的計算方法有着千絲萬縷的關系。
先看看計算數組下標源碼:

由上圖我們可以看到,<key,value>要放到數組的那個位置,它會通過key的hash值和數組長度-1進行與運算來計算得出。也就是
(n - 1) & hash

這里n就是數組長度。 可以看出一旦數組擴容,算式中n就發生了變化,那么原來元素下標也會發生變化,<key,value>就要移動位置。
如果每一次擴容所有的<key,value>都要移動,勢必帶來性能上的不足。
但是當擴容是2倍,我們就會發現非常有趣的地方。
我們來看一下hashmap的擴容過程。
16(默認)-> 32(擴容一次) -> 64(擴容兩次)
從10進制中我們或許發現不了什么,但是它是進行與運算所以咱們只要二進制,這時就有點意思了。

0001 0000    //16二進制    
0010 0000    //32二進制  
0100 0000    //64二進制

-1之后則變為

0000 1111     
0001 1111  
0011 1111 

比如現在我們有三個<key,value>要插入,通過計算key的hash值分別為

0101 1010 0011 1101
0101 1010 0011 1101
1110 0100 0001 0001

代入計算之后

hashCode(計算的hash值只用高16) size=16 size=32 是否移位
1010 0011 1101 1010 0011 1101&1111 1010 0011 1101&11111 向前移動16位
1010 0011 1101 1010 0011 1101&1111 1010 0011 1101&11111 不用移位
0100 0001 0001 0100 0001 0001&1111 0100 0001 0001&11111 向前移動16位

我們發現,擴容后是否移位,由擴容后key的hashcode參與計算的最高位是否1為所決定,並且移動的方向只有一個,即向高位移動。因此,可以根據對最高位進行檢測的結果來決定是否移位,從而可以優化性能,不用每一個元素都進行移位,

是否移位,由擴容后表示的最高位是否1為所決定,並且移動的方向只有一個,即向高位移動。因此,可以根據對最高位進行檢測的結果來決定是否移位,從而可以優化性能,不用每一個元素都進行移位。最高位為0 與運算之后的值依然與之前相同說明不用向高位移動。為1則需要向高位移動。

結論,原因有二:

第一哈希函數的問題 將元素充分散列,避免不必要的哈希沖突。
通過除留余數法方式獲取桶號,因為Hash表的大小始終為2的n次冪,因此可以將取模轉為位運算操作,提高效率,容量n為2的冪次方,n-1的二進制會全為1,位運算時可以充分散列,避免不必要的哈希沖突。
第二就是擴容時桶內元素是否向高位移動的問題。擴容為2倍,參與計算的hashcode高位為1則移動,為0則不移動,也就是說一個桶內元素只有一半的概率需要移動,從而優化了性能。


免責聲明!

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



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