根据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)
。
我错过了什么吗?
答案 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(由于性能原因)。