大家在查看hashmap的底层原理时都会看到“hashmap再申请生成新的数组结构时其数组元素个数是2的幂”。
这是为什么呢? 不是2的幂就不可以吗? 大家可能相等这可能和内存的分配有关系,可以提升内存分配速度,或者方便元素的查找等。
在具体解释前先说下hashmap的元素的查找:
代码在获取hashmap数据结构中的每个key的值时:
- 先将key进行hash函数的计算,获取到一个大的整数
- 使用大的整数 h%L (L是数组长度)
- 找到对应的数组下标,比较存储的key和查找key是否一致,不一致时,如果后面还有链表就进行遍历。
从上面可以看到每次进行查找时都需要进行取模运行,而cpu对于取模运算时比较慢的,而对于逻辑与 或 非运算很快,比较是二进制位处理。如果数组元素个数是2的幂时就可以将取模运算转化为与运算,大大提高计算速度:
h%L = h&(L-1)
现在咱们证明下上面得结论:
- h(key进行hash后的大整数)
- length(数组长度,2的幂)length=2^x
假设h小于length:
h小于length时 h%length=h
length-1=2^0+2^1+.....2^(x-1)(根据2进制的规则可以转为这种形式) 可以看到所有位都是1,h<=length-1,这样不管如何只要h对应二进制位位1时,length-1对应的二进制位都是1.
可以得出结论: h&(length-1)=h=h%length;
假设h大于length:
- h=n+m*length
- h%length=n (n<length)
- length=2^x;
- length-1=2^0+2^1+.....2^(x-1)
- h&(length-1)=(n+m*length)&(2^0+2^1+.....2^(x-1))
其中m*length转化为二进制时,其与length-1的与操作结果都是0(因为length=2^x, 变大m倍时,其变为二进制是等于2^Y1+2^Y2+2^Y3...,其中Y>=x)
所以 (n+m*length)&(2^0+2^1+.....2^(x-1)) = n;
得出结论 h%length = h&(length-1)