HashMap计算key索引算法为什么是hash(key)&(n = table.length - 1)

前置知识 在代码中 Map map = new HashMap(3) 这样实例化一个map对象后,map的table长度实际是多少? 答案是4,在HashMap底层,会根据用户设置的长度num变更为比num大的最近的一个2^n数,如果未设置则是默认16
HashMap计算key索引算法为什么是hash(key)&(n = table.length - 1)
文章图片

index计算源代码 HashMap计算key索引算法为什么是hash(key)&(n = table.length - 1)
文章图片

按常理来说 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的数减掉。

    推荐阅读