当为HashMap定义初始大小时:
会执行这个方法。
看这个方法的官方注释,说明这个方法会基于所给的自定义容量,返回一个2的倍数的数值。
所以,如果我们要为HashMap初始化一个容量,那么实际容量也依然会是2的倍数,比如如果定义的容量是3,那么实际上HashMap的容量将会是4。
再看看这个属性,这是HashMap用来存放数据的哈希表。
根据官方解释可以知道,这张表的长度总会是2的倍数。
为什么HashMap的作者一定要规定table的长度必须是2的倍数?
我们来找找原因。
首先需要知道,对于任何2^n的数,比如8, 16,这些数值的二进制表示总会是100…0的形式,也就是,最高位为1,剩余位全为0。
而对于任何(2^n)-1的数,在二进制下的表现形式总会是1111…1的形式,也就是一串全为1的二进制数值。
现在举两个二进制除法的例子:
比如,Y=101110,且X=1000,则Y / X:
得到余数:110。
再比如,Y=100110,且X=1000,则Y / X:
得到余数:110。
观察可知,在二进制运算中,如果除数是2的n倍,那么余数的数值完全可以基于(被除数0~n位 - 除数)计算得到。
即,如果Y=101110,X=1000,那么Y(0~n位) - X=1110-1000=110=Y%X。
更进一步观察可知,被除数0~(n-1)位的这串二进制数值串,其实直接就等同于Y%X的结果。
通过与一串全为1的二进制数值串做&(且)操作,就能够得到原数值串,所以,Y & (X-1) = 101110 & 111 = 110,110是Y中0~(n-1)的数值串,这个数值串就是Y%X的计算结果。
所以,正是由于二进制运算的这种特性,HashMap在put进一个新元素到哈希表时,如果哈希表的长度为2的倍数,那么就可以直接通过(n - 1) & hash得到 n%hash的结果了。
在计算机中,由于位运算的执行效率要比%运算高效很多,所以,通过做位运算,而不是%运算,就能够大大提高对哈希表操作的效率了。