假设我知道HashMap
中的键值对的确切数量,并且我知道它不是2的幂。在这些情况下,我应该指定初始容量吗?我可以得到最近的2的幂并指定但仍然我想知道在这种情况下哪个更好的事情(当我不想计算最接近的2的幂时)。
谢谢!
答案 0 :(得分:4)
如果查看java.util.HashMap源代码(java 1.7)(可以在JDK' s目录的src.zip文件中找到),你会看到HashMap的put方法使用inflateTable
方法创建一个存储HashMap条目的数组,该方法总是将HashMap的容量增加到大于(或等于)指定大小的2的幂。
以下是方法:
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的幂,则无关紧要。
答案 1 :(得分:3)
您应该考虑初始容量,提示HashMap
近似预期的数据。通过提供正确的初始容量,您可以最小化地图必须重建的次数以便向上扩展。例如,如果您知道计划插入一百万条记录,通过构建具有1,000,000初始容量的地图,它将确保在构造时分配足够的内存来处理那么多插入。在此之后,未来在地图中的插入可能需要在map.put()
调用期间进行大量O(n)操作才能调整大小。
将此初始容量视为提示,而不是您期望HashMap
遵循的指示,可能会帮助您确定您所描述的优化是不必要的。 HashMap
旨在在所有正常情况下都表现良好,因此虽然提供初始容量可能会有所帮助,但它通常不会对您的代码产生巨大影响,除非您构建许多< / em>新的大型地图。在这种情况下,指定容量将避免中间表调整大小,但这是全部。
As documented,如果你指定的太多大的初始容量,你可能会引入一些不必要的减速:
对集合视图的迭代需要与&#34;容量成比例的时间&#34;
HashMap
实例
然而在实践中,分配这么大的地图的浪费内存可能会比稍慢的迭代速度更快地给你带来问题。
请务必阅读Why does HashMap require that the initial capacity be a power of two?。
您可能会考虑改为Guava ImmutableMap实施;如果您事先知道地图的内容,并且不希望更改它们,那么不可变的集合将更容易使用use less memory than their mutable counterparts。
我在这里进行了一些快速检查,我使用Scala的REPL(以及一些个人实用功能)来检查HashMap
内部的内容(Java 1.7):
// Initialize with capacity=7
scala> new HashMap[String,String](7)
res0: java.util.HashMap[String,String] = {}
scala> getPrivate(res0, "table").length
res1: Int = 8
scala> ... put 7 values
// Still internally using the same array
scala> getPrivate(res0, "table").length
res9: Int = 8
// Specifying capacity 9 allocates a 16-lenth array
scala> getPrivate(new HashMap[String,String](9), "table").length
res10: Int = 16
// Copying our first map into a new map interestingly
// also allocates the default 16 slots, rather than 8
scala> getPrivate(new HashMap[String,String](res0), "table").length
res11: Int = 16
scala> ... put 10 more values in our map
scala> getPrivate(res0,"table").length
res22: Int = 32
// Copying again immediately jumps to 32 capacity
scala> getPrivate(new HashMap[String,String](res0),"table").length
res23: Int = 32