在HashMap
中:(h = key.hashCode()) ^ (h >>> 16);
在ConcurrentHashMap
中:(h ^ (h >>> 16)) & HASH_BITS;
其中HASH_BITS
是0x7fffffff
,到& HASH_BITS
,它始终可以是正数。
答案 0 :(得分:1)
为什么HashMap(JDK1.8)中的哈希计算不需要像ConcurrentHashMap那样考虑负的hashCode? p>
最终,在HashMap
情况下,也需要考虑散列为负(扩展后)的情况。只是这会在代码的后面发生。
例如,在getNode
(Java 8)中,您会发现:
Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
if ((tab = table) != null && (n = tab.length) > 0 &&
(first = tab[(n - 1) & hash]) != null) {
由于tab.length
是2的幂,所以tab.length - 1
是用于将hash
简化为数组下标的合适位掩码。
您可以放心,在HashMap
或ConcurrentHashMap
的每个实现中,都有一些代码将哈希码减少为适合用作下标的数字。它会在那里...某处。
但是...也不希望这些类的代码易于阅读。所有收集类都经过重新加工/调整多次,以在各种测试用例中获得最佳(平均)性能。
答案 1 :(得分:0)
实际上,它处理负索引计算。乍一看并不明显,但是在访问元素(键或值)时某些地方会有计算。
int index =
(n - 1) & hash
,其中n
是表格的长度
它只是处理负索引。
AFAIK,HashMap
始终使用大小为2的幂的数组(例如16
,32
,64
等)。
假设我们的容量为256
(0x100
(2^8
)。
减去1后,我们得到256 - 1 = 255
,即0x100 - 0x1 = 0xFF
减法产生了从0
到length-1
之间的正确的存储区索引,其中包含按位需要的确切位掩码以及哈希。
256 - 1 = 255
0x100 - 0x1 = 0xFF
260
(0x104
)的散列与0xFF
按位与,以生成4
的存储区编号。
257
(0x101
)的散列与0xFF
按位与,以生成1
的存储区编号。