根据默认值,HashMap不会重新散列

时间:2014-07-01 05:57:10

标签: java hash hashmap hashtable

根据Java文档

  

HashMap的一个实例有两个影响其性能的参数:   初始容量和负载系数。容量是数量   哈希表中的桶,而初始容量就是   创建哈希表时的容量。负载系数是a   衡量哈希表在其之前可以获得多长的度量   容量自动增加。当中的条目数   哈希表超出了加载因子和当前的乘积   容量,哈希表重新哈希(即内部数据   重建结构),以便哈希表大约两次   桶的数量。

并且

 the default initial capacity is 16 and the default load factor is 0.75.

根据以上所述,HashMap的阈值为12(16 * 0.75),并且在放置第13个元素时应重新散列HashMap。

我创建了一个空的HashMap并在其中放入了16个元素。我在调试模式下运行它。当第13个元素被放置时,我检查了调试变量,并惊讶地看到阈值仍为12(as opposed to 24)且表数组仍包含16 entries(as opposed to 32)。只有在放置第16个元素之后,哈希表才会被重新定义,使得阈值24(32 * 0.75)

我错过了什么吗?

1 个答案:

答案 0 :(得分:6)

我在HashMap(Java 7)的源代码中找到了答案。设置值将运行此代码:

public V put(K key, V value) {
    [...]
    modCount++;
    addEntry(hash, key, value, i);
    return null;
}

有趣的调用是添加条目的方法。让我们来看看这个方法的来源:

void addEntry(int hash, K key, V value, int bucketIndex) {
    if ((size >= threshold) && (null != table[bucketIndex])) {
        resize(2 * table.length);
        hash = (null != key) ? hash(key) : 0;
        bucketIndex = indexFor(hash, table.length);
    }
    createEntry(hash, key, value, bucketIndex);
}

正如我们所看到的那样,仅在尺寸超过阈值时才进行调整大小计算的存储桶(用于放置条目)不为空。

这种行为是有道理的。只要每个条目进入一个空桶,就不需要调整大小,因为每个条目都位于桶列表的第一个位置,因此很容易找到。 这完全取决于性能。事实上,有许多实现细节表现得非常好。

编辑(因为Java 6和Java 7之间存在差异):

上面的源代码来自Java 7.实际上,在Java 6中,调整大小行为仅取决于大小和阈值。这是Java 6中addEntry方法的来源:

void addEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex];
    table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
    if (size++ >= threshold)
        resize(2 * table.length);
}

这实际上意味着HashMap实现从Java 6更改为Java 7(由于性能原因)。