为什么HashMap要求初始容量为2的幂?

时间:2011-12-02 06:03:06

标签: java hashmap hashtable hash

当我看到以下

时,我正在浏览Java的HashMap源代码
//The default initial capacity - MUST be a power of two.
static final int DEFAULT_INITIAL_CAPACITY = 16;

我的问题是为什么这个要求首先存在?我还看到允许创建具有自定义容量的HashMap的构造函数将其转换为2的幂:

int capacity = 1;
while (capacity < initialCapacity)
  capacity <<= 1;

为什么容量总是必须是2的幂?

此外,当执行自动重组时,究竟会发生什么?哈希函数也改变了吗?

2 个答案:

答案 0 :(得分:43)

映射必须确定要用于任何给定键的内部表索引,将任何int值(可能为负)映射到范围[0, table.length)中的值。当table.length是2的幂时,可以真正廉价地完成 - 并且在indexFor中:

static int indexFor(int h, int length) {
    return h & (length-1);
}

使用不同的表长度,您需要计算余数并确保它是非负的。这绝对是微优化,但可能是有效的:)

  

此外,当执行自动重组时,究竟会发生什么?哈希函数也改变了吗?

我不太清楚你的意思。使用相同的哈希码(因为它们只是通过在每个键上调用hashCode来计算),但由于表长度的变化,它们将在表中以不同的方式分布。例如,当表长度为16时,5和21的哈希码最终都存储在表条目5中。当表长度增加到32时,它们将位于不同的条目中。

答案 1 :(得分:4)

理想情况实际上是使用HashMap的后备数组的素数大小。这样,您的密钥将更自然地分布在整个阵列中。然而,这适用于mod分区,并且每次发布Java时操作都变得越来越慢。 从某种意义上说,2方法的强大功能是您可以想象的最差的表大小,因为糟糕的哈希码实现更有可能在阵列中产生密钥崩溃。

因此,您将在Java的HashMap实现中找到另一个非常重要的方法,即hash(int),它可以补偿糟糕的哈希码。