1. 程式人生 > 實用技巧 >HashMap原始碼中的位運算子&

HashMap原始碼中的位運算子&

引言

最近在讀HashMap原始碼的時候,發現在很多運算子替代常規運算子的現象。比如說用hash & (table.length-1) 來替代取模運算hash&(table.length);用if((e.hash & oldCap) == 0)判斷擴容後元素的位置等等。

1.取模運算子%底層原理

​ 總所周知,位運算&直接對二進位制進行運算;而對於取模運算子%:a % b 相當於 a - a / b * b,底層實際上是除法器,究其根源也是由底層的減法和加法共同完成。所以其執行效率要遠遠小於位運算子&。

2.位運算子&如何實現取模功能

​ 我們先來看兩個例子

5 & 7                9 & 7
0101----5            1001----9
&                    &
0111----7            0111----7
=                    =
0101----5            0001----1

​ 確實,hash & (table.length-1) 來實現了運算hash&(table.length)從二進位制的角度來說,5%8實際上是將二進位制5(0101)向右移動3位,而與7(0111)進行與運算實際上就是將位數向右移動三位。不過要注意的是,只有當length的長度為2^n時,結論才成立。

3.位運算子&在if((e.hash & oldCap) == 0)判斷擴容後元素的位置

​ 這是出自於JDK1.8中擴容函式resize()的一行程式碼,用於判斷在擴容後原陣列中的元素是否需要移動。舉個例子:

0001 1010----26                0000 1010----10                 
&                              &
0001 0000----16                0001 0000----16
=                              =
0001 0000----非0               0000 0000-----0

利用hash值和oldCap進行與運算,很明顯當結果大於0代表hash值大於oldCap時,下標位置變為舊陣列的下標j + oldCap;若結果等於0代表小於oldCap,則下標位置不變。相比於JDK1.7重新計算每個元素的雜湊值,通過高位運算(e.hash & oldCap)無疑效率更高。