前置知识
在代码中 Map map = new HashMap(3)
这样实例化一个map对象后,map的table长度实际是多少?
答案是4,在HashMap底层,会根据用户设置的长度num变更为比num大的最近的一个2^n数,如果未设置则是默认16
文章图片
index计算源代码
文章图片
按常理来说 index = hash(key) % n
,那为什么 hash & (n-1) 和 取模效果一样呢?
因为n的大小是2的幂次方,所以hash(key) % n == hash & (n-1)
解释:
n表示哈希桶的长度,就是hashmap这个实例的容量,刚才说了会是2^n^,不设置默认是16,那为什么要减1,我们知道16的二进制是10000,减1后就变成1111,这样我们有了一个二进制全部为1的数后就可以和hash值进行&运算。
&:按位与,都为1才是1
// 假设我的哈希桶的长度是16
// n - 1 即为 15
// 二进制表示为 1111
// 假设 hash值 是 111101001001101010101010111011
// 即
111101001001101010101010111011 // hash
000000000000000000000000001111 // n-1
000000000000000000000000001011 // 结果为 1011 即 11
此时数据插入到第11的位置,这个完全取决于哈希桶的长度。就算你最后几位都是1,你插的位置还是在n-1的范围内,这就是为什么和取模的效果一样。
虽然通过&运算之后算出来的index肯定在哈希桶的长度之内,但是为什么就那么确定得到的值是和%运算是一样的呢?
而一个数模上一个偶数(n),结果肯定是小于这个偶数的值,即在
[0, n)
范围内,这个值也是这个数除n除不尽的最后的数,而用二进制表示这个数的时候肯定也就是这个二进制末尾的数,那么是末尾几位的数呢?答案不言而明,也就是
2^x=n
这个表达式的x的值; 可能还会疑惑,为什么
&
后面的数和%
后之后剩下的数一定是相等的呢? 上面hash值太大,举一个hash小一点的数比如十进制的123,
123%16==11
123除多少个16得到余数是11呢,是7个0111 1011 // 十进制为 123
- 0111 0000 // 十进制为 16 + 16^2 + 64^4
= 0000 1011 // 十进制为 11
【HashMap计算key索引算法为什么是hash(key)& (n = table.length - 1)】所以余数即计算后的index的值取决于table的length,就把该hash的二进制从右到左x位数置为0的数减掉。