一直知道HashMap有默认的容量和加载因子,今天想看看源代码,希望能了解的更清楚一些。
我们先看看默认的构造器吧,以下为我本机的JDK6.0的源代码.
欢迎访问老紫竹的网站(http://www.java2000.net)和我在CSDN的博客(http://blog.csdn.net/java
/**
* 默认的初始化的容量,必须是2的幂次数
* The default initial capacity - MUST be a power of two.
*/
staticfinalintDEFAULT_INITIAL_CAPACITY =16;
/**
* 默认的加载因子
*/
staticfinalfloatDEFAULT_LOAD_FACTOR =0.75f;
/**
* 下一个需要重新分配的尺寸值。等于容量乘以加载因子。
* 也就是说,一旦容量到了这个数值,将重新分配容器的尺寸。
* The next size value at which to resize (capacity * load factor).
* @serial
*/
intthreshold;
publicHashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR;
threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
table =newEntry[DEFAULT_INITIAL_CAPACITY];
init();
}
欢迎访问老紫竹的网站(http://www.java2000.net)和我在CSDN的博客(http://blog.csdn.net/java
从代码可以看出,默认的容量是16,而 threshold是16*0.75 = 12;
我们来看看增加的部分代码。
publicV put(K key, V value) {
// 我们忽略掉这部分的代码,只看我们这里最关心的部分
addEntry(hash, key, value, i);// 这里增加了一个Entry,我们看看代码
returnnull;
}
voidaddEntry(inthash, K key, V value,intbucketIndex) {
Entry e = table[bucketIndex];
table[bucketIndex] =newEntry(hash, key, value, e);
if(size++ >= threshold)// 这里是关键,一旦大于等于threshold的数值
resize(2* table.length);// 将会引起容量2倍的扩大
}
voidresize(intnewCapacity) {
Entry[] oldTable = table;
intoldCapacity = oldTable.length;
if(oldCapacity == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return;
}
Entry[] newTable =newEntry[newCapacity];// 新的容器空间
transfer(newTable);// 复制数据过去
table = newTable;
threshold = (int)(newCapacity * loadFactor);// 重新计算threshold的值
}
好了,我想我们已经清楚大部分了。
其中有一点,起始容量必须是2的幂次,这如何保证呢?我们来看看其构造方法
publicHashMap(intinitialCapacity,floatloadFactor) {
// 忽略掉一部分代码....
// Find a power of 2 >= initialCapacity
// 重新查找不比指定数值大的最大的2的幂次数
intcapacity =1;
while(capacity < initialCapacity)
capacity <<=1;
// 其它的初始化代码 ...
}
好了,关于起始容量和加载因子的探讨我们就到这里了。我们应该有了一定的了解了。
总结:
相对准确的估算数据量,将极大的影响HashMap的性能,因为resize是一个重新分配的过程,耗时应该是里面最大的。
加载因子较小,会有更多的空间空闲,我不知道这个0.75是不是一个折中方案。也许0.9也是一个不错的选择,特别是那些数据量虽然很大,但不是经常变化的地方,比如公司人员,城市列表等相对比较固定的数据