为什么HashMap(JDK1.8)中的哈希计算不需要像ConcurrentHashMap那样考虑负的hashCode?

时间:2018-08-17 10:29:18

标签: java hashmap concurrenthashmap

HashMap中:(h = key.hashCode()) ^ (h >>> 16);

ConcurrentHashMap中:(h ^ (h >>> 16)) & HASH_BITS;

其中HASH_BITS0x7fffffff,到& HASH_BITS,它始终可以是正数。

2 个答案:

答案 0 :(得分:1)

  

为什么HashMap(JDK1.8)中的哈希计算不需要像ConcurrentHashMap那样考虑负的hashCode?

最终,在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简化为数组下标的合适位掩码。

您可以放心,在HashMapConcurrentHashMap个实现中,都有一些代码将哈希码减少为适合用作下标的数字。它会在那里...某处。

但是...也不希望这些类的代码易于阅读。所有收集类都经过重新加工/调整多次,以在各种测试用例中获得最佳(平均)性能。

答案 1 :(得分:0)

实际上,它处理负索引计算。乍一看并不明显,但是在访问元素(键或值)时某些地方会有计算。

int index = (n - 1) & hash ,其中n是表格的长度

它只是处理负索引。

AFAIK,HashMap始终使用大小为2的幂的数组(例如163264等)。

假设我们的容量为2560x1002^8)。 减去1后,我们得到256 - 1 = 255,即0x100 - 0x1 = 0xFF 减法产生了从0length-1之间的正确的存储区索引,其中包含按位需要的确切位掩码以及哈希。

256 - 1 = 255
0x100 - 0x1 = 0xFF

2600x104)的散列与0xFF按位与,以生成4的存储区编号。

2570x101)的散列与0xFF按位与,以生成1的存储区编号。