为什么HashMap在索引上插入新节点(n-1)&哈希?

时间:2014-12-01 14:48:00

标签: java hash collections hashmap hashcode

为什么HashMap在索引上插入新节点: tab[(n - 1) & hash]

hash = key.hashCode() ^ key.hashCode() >>> 16 n = tab.length数组的Node<K,V>

为什么HashMap没有像这样放置节点:tab[hash]?它只是另一个散列函数,比如在大多数hashCode()方法中乘以31吗? 在此先感谢您的解释!

2 个答案:

答案 0 :(得分:9)

因为hash可能超出范围。

&#34;规范解决方案&#34;是采用数组长度的散列的(正)模数,这段代码使用的事实是数组具有两个幂的长度来用变量替换昂贵的模数(模数常量被很好地优化) )用便宜的按位AND。

答案 1 :(得分:8)

哈罗德的一个很好的描述,但我觉得没有一个例子是不够的。所以继承人 -

每当创建一个新的Hasmap时,内部Node []表的数组大小总是2的幂,并且以下方法保证它 -

static final int tableSizeFor(int cap) {
    int n = cap - 1;
    n |= n >>> 1;
    n |= n >>> 2;
    n |= n >>> 4;
    n |= n >>> 8;
    n |= n >>> 16;
    return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}

因此,假设您提供的初始容量为5

cap = 5
n = cap - 1 =  4 = 0 1 0 0
n |= n >>> 1;    0 1 0 0 | 0 0 1 0 = 0 1 1 0 = 6
n |= n >>> 2;    0 0 1 1 | 0 1 1 0 = 0 1 1 1 = 7
n |= n >>> 4;    0 0 0 0 | 0 1 1 1 = 0 1 1 1 = 7
n |= n >>> 8;    0 0 0 0 | 0 1 1 1 = 0 1 1 1 = 7
n |= n >>> 16;   0 0 0 0 | 0 1 1 1 = 0 1 1 1 = 7
return n + 1     7 + 1 = 8 

因此表格大小为8 = 2 ^ 3

现在可以将元素放在地图中的索引值为0-7,因为表大小为8.现在让我们看看put方法。它查找桶索引如下 -

Node<K,V> p =  tab[i = (n - 1) & hash];

其中n是数组大小。所以n = 8.和说

一样
Node<K,V> p =  tab[i = hash % n];

所以我们现在需要看到的是如何

hash % n == (n - 1) & hash

让我们再举一个例子。让我们说一个值的哈希是10。

hash = 10
hash % n = 10 % 8 = 2
(n - 1) & hash = 7 & 10 = 0 1 1 1 & 1 0 1 0 = 0 0 1 0 = 2

希望这会有所帮助。 More details

PS:上面的链接转到我的博客,其中有更详细的示例解释。