如果所有条目以链接方式存储在相同索引下,为什么HashMap空间会扩展

时间:2012-12-27 10:23:50

标签: java optimization hashmap

从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);
        }

3 个答案:

答案 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)

这是一个交易。当大小较小时,同一桶中的所有元素将变得分散,同时大小增加。这提高了性能。