1. 程式人生 > 其它 >為什麼HashMap擴容是2倍以及容量為什麼是2的n次冪

為什麼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則不移動,也就是說一個桶內元素只有一半的概率需要移動,從而優化了效能。