Jdk1.8初始化hashMap容量的算法
static final int tableSizeFor(int cap) {
// 先减1,避免传进来的本来就是2的n次幂,导致算出来多了一次幂,比如传16会得到32,实际上16即可
int n = cap - 1;
// 低位全部变1, int4字节*1个字节8位=32位
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
//再加1获取2的N次幂作为容量
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
举例,Map map = new hashMap(10)
10-1=9
对应二进制 0000 1001
右移1位 0000 0100
或运算 0000 1101
结果右移2位 0000 0011
或运算 0000 1111
结果右移4位 0000 0000
或运算 0000 1111
```
不断右移然后或运算后,最后低位全部变1
加1后 得到 0001 0000 得到16为最接近10的二的次方数
hashmap数组容量2的N次幂的好处是:
查看put方法计算元素数组下标核心代码
i = (n - 1) & hash
由于N为2的N次幂,N减1后得到高位为0,低位全为1的二进制
进行与运算后,不可能得到比N大的数
举例:
n= 16,则n-1的二进制为0000 1111
假设hashcode为**** ****
与运算后,必定得到 0000 ****,所以不可能大于16,范围为00000000-00001111,即不存在数组越界问题
这里又会引申出一个问题,这样的话,hashCode的高位的****不是没用了吗,与0000进行与运算后都是0000
所以在计算hashCode的算法中,会对算出来的hashCode进行右移然后异或运算,使得高位的值保留到低位中去
举例 hashcode 为1010 0100
假设右移4位 0000 1010
异或运算 1010 1110
这样高位的这两个1就不会完全丢失了