从java HashMap's source code可以看出,当达到空间阈值时,它的空间会扩展两次。
我想到了一个用例,其中所有6个元素以链接的方式存储在相同的索引下。当第7个元素到达时,阈值为7(10 * .75)的HashMap(大小为10)会扩展。实际上这里不需要扩展,因为所有都保存在一个索引下。
亲切地启发我 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);
}
void resize(int newCapacity)
{
Entry[] oldTable = table;
int oldCapacity = oldTable.length;
if (oldCapacity == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return;
}
Entry[] newTable = new Entry[newCapacity];
transfer(newTable);
table = newTable;
threshold = (int)(newCapacity * loadFactor);
}
答案 0 :(得分:2)
你说没有必要调整大小,因为HashMap
可以保存这些条目。
但理想情况下,HashMap
应提供持续访问时间(O(1)
)。调整大小是为了尝试提供此访问时间。通过重新组织存储桶,对键的查找应理想地引用仅具有一个值的存储桶(以避免遍历条目列表)。
在get()
方法中,您会找到以下这一行:
for (Entry<K,V> e = table[indexFor(hash, table.length)];
HashMap使用indexFor()
方法识别存储桶,然后它将遍历存储桶以查找匹配的密钥。为了优化这一点,理想情况下迭代应该只发生一次(你无法避免桶查找)
这指出理想情况下,哈希码在int
范围内均匀分布(2 ^ 31-1)。您可以使对象哈希码保持不变(例如1),但是您可以看到HashMap无法执行任何操作,只会将所有条目转储到一个存储桶中,从而影响性能。
答案 1 :(得分:1)
这只是一个设计决定。可能基于以下事实:地图在检索和存储方面应该非常快,如果最终链接这么多条目,性能将受到影响。因此,重新散列可能会使您的项目在桶中稀疏,而不是仅将它们链接在一个桶中。
答案 2 :(得分:0)
这是一个交易。当大小较小时,同一桶中的所有元素将变得分散,同时大小增加。这提高了性能。