Java 指定HashMap';当它不是2的幂时,它的初始容量比完全不指定的大多少?

Java 指定HashMap';当它不是2的幂时,它的初始容量比完全不指定的大多少?,java,hashmap,java-6,Java,Hashmap,Java 6,假设我知道将进入HashMap的键值对的确切数目,并且我知道它不是2的幂。在这些情况下,我是否应该指定初始容量?我可以得到2的最接近的幂并指定它,但我仍然想知道在这种情况下(当我不想计算2的最接近幂时)哪一个更好 谢谢 如果您查看java.util.HashMap源代码(java 1.7)(您可以在JDK目录中的src.zip文件中找到)您将看到HashMap的put方法使用inflateTable方法创建存储HashMap条目的数组,并且该方法始终将HashMap的容量增加到大于(或等于)指定

假设我知道将进入
HashMap
的键值对的确切数目,并且我知道它不是2的幂。在这些情况下,我是否应该指定初始容量?我可以得到2的最接近的幂并指定它,但我仍然想知道在这种情况下(当我不想计算2的最接近幂时)哪一个更好


谢谢

如果您查看java.util.HashMap源代码(java 1.7)(您可以在JDK目录中的src.zip文件中找到)您将看到HashMap的put方法使用
inflateTable
方法创建存储HashMap条目的数组,并且该方法始终将HashMap的容量增加到大于(或等于)指定大小的二次方

方法如下:

    private void inflateTable(int toSize) {
        // Find a power of 2 >= toSize
        int capacity = roundUpToPowerOf2(toSize);

        threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);
        table = new Entry[capacity];
        initHashSeedAsNeeded(capacity);
    }

因此,您指定的大小是否为2的幂并不重要。

如果您查看java.util.HashMap源代码(java 1.7)(您可以在JDK目录中的src.zip文件中找到)您将看到HashMap的put方法使用
inflateTable
方法创建存储HashMap条目的数组,并且该方法始终将HashMap的容量增加到大于(或等于)指定大小的二次方

方法如下:

    private void inflateTable(int toSize) {
        // Find a power of 2 >= toSize
        int capacity = roundUpToPowerOf2(toSize);

        threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);
        table = new Entry[capacity];
        initHashSeedAsNeeded(capacity);
    }

因此,不管你指定的大小是两个幂的大小。

< P>你应该考虑初始容量,这是对“代码> HashMap <代码>的提示。通过提供正确的初始容量,可以最大限度地减少为放大而必须重建地图的次数。例如,如果您知道计划插入一百万条记录,那么通过构建初始容量为1000000的映射,它将确保在构建时分配足够的内存来处理如此多的插入。在此之后,在
map.put()
调用过程中,将来插入到映射中可能需要一个大的O(n)操作才能调整大小

将此初始容量视为一个提示,而不是期望
HashMap
遵循的指令,可能会帮助您看到您描述的优化是不必要的
HashMap
被设计为在所有正常情况下都能表现良好,因此,虽然提供初始容量可能会有所帮助,但通常不会对代码产生巨大影响,除非您一直在构建许多新的大型映射。在这种情况下,指定容量可以避免调整中间表的大小,但仅此而已

,如果指定的初始容量过大,则可能会引入一些不必要的减速:

对集合视图的迭代需要与
HashMap
实例的“容量”成比例的时间

然而,在实践中,分配如此大的映射所浪费的内存可能会比稍微慢一点的迭代速度更快地给您带来问题

确保你也阅读


你可以考虑的一件事是转向实施;如果您事先知道地图的内容,并且不希望对其进行更改,那么不可变集合将更易于使用和修改


下面是我使用Scala的REPL(和一些个人实用程序函数)进行的一些快速检查,以检查
HashMap
(Java 1.7)内部的情况:


您应该考虑初始容量,这是对“代码> HashMap <代码>的提示。通过提供正确的初始容量,可以最大限度地减少为放大而必须重建地图的次数。例如,如果您知道计划插入一百万条记录,那么通过构建初始容量为1000000的映射,它将确保在构建时分配足够的内存来处理如此多的插入。在此之后,在

map.put()
调用过程中,将来插入到映射中可能需要一个大的O(n)操作才能调整大小

将此初始容量视为一个提示,而不是期望
HashMap
遵循的指令,可能会帮助您看到您描述的优化是不必要的
HashMap
被设计为在所有正常情况下都能表现良好,因此,虽然提供初始容量可能会有所帮助,但通常不会对代码产生巨大影响,除非您一直在构建许多新的大型映射。在这种情况下,指定容量可以避免调整中间表的大小,但仅此而已

,如果指定的初始容量过大,则可能会引入一些不必要的减速:

对集合视图的迭代需要与
HashMap
实例的“容量”成比例的时间

然而,在实践中,分配如此大的映射所浪费的内存可能会比稍微慢一点的迭代速度更快地给您带来问题

确保你也阅读


你可以考虑的一件事是转向实施;如果您事先知道地图的内容,并且不希望对其进行更改,那么不可变集合将更易于使用和修改


下面是我使用Scala的REPL(和一些个人实用程序函数)进行的一些快速检查,以检查
HashMap
(Java 1.7)内部的情况:


如果内存可用,它会四舍五入到最接近的2次方,所以请指定一个初始容量。@user3580294我查看了源代码,但它不是。只有使用构造函数mit另一个
Map
作为参数时才会发生这种情况。我肯定在
initialCapacity
构造函数的源代码中,在
tableSizeFor()
方法下看到了它。查看Oracle 1.8.0_05源代码。@user3580294在Oracle 1.7.0_51的
java.util.HashMap
中没有这样的东西。