为什么哈希表 11 的初始容量是 11,而哈希映射中的DEFAULT_INITIAL_CAPACITY是 16,需要 2 的幂?

2022-09-01 10:56:04

比较JDK 1.6中的和源代码,我在HashMap中看到了下面的代码:HashMapHashtable

/**
 * The default initial capacity - MUST be a power of two.
 */
static final int DEFAULT_INITIAL_CAPACITY = 16;

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

但是,在Hashtable中,我看到了这个:

table = new Entry[initialCapacity];

public Hashtable() {
    this(11, 0.75f);
}

所以我的问题是:为什么HashMap需要2的幂作为初始容量,而Hashtable选择11作为默认的初始容量?我认为这与 Hashtable 是线程安全的,不允许空键或值无关。


答案 1

以下文章详细地解决了这个问题:HashMap需要更好的hashCode() - JDK 1.4 Part II

根据那篇文章,转向两次幂大小的主要原因是位屏蔽比整数除法更快。这并非没有不良后果,原作者之一对此进行了解释:

Joshua Bloch:使用二次幂的缺点是,生成的哈希表对哈希函数(hashCode)的质量非常敏感。输入中的任何更改都必须影响哈希值的低阶位。(理想情况下,它应该以相等的可能性影响哈希值的所有位。因为我们不能保证这是真的,所以我们在切换到二次幂哈希表时放入了一个辅助(或“防御”)哈希函数。此哈希函数在屏蔽低阶位之前应用于哈希代码的结果。它的工作是将信息分散到所有位上,特别是低阶位。当然,它必须运行得非常快,否则您将失去切换到两个大小的桌子的好处。1.4 中原来的辅助哈希函数被证明是不够的。我们知道这是一种理论上的可能性,但我们认为它不会影响任何实际的数据集。我们错了。替换辅助哈希函数(我借助计算机开发)具有很强的统计属性,几乎可以保证良好的存储桶分布。


答案 2

Hashtable使用伪素数表大小,并且相对较慢地增加表的大小。HashMap使用2的幂作为位明智的,并且比使用模数更快。

具有讽刺意味的是,2次幂的模量意味着需要一个好的hashCode(),因为顶部的位将被忽略,所以HashMap有一种方法可以重新排列哈希码,以避免这个问题,这意味着它实际上可以更慢。:Z