问题
JDK1.7中一个HashMap中是否会出现size>threshold情况?
我这里使用的是jdk1.7.0_67版本。
背景知识
了解HashMap的同学都知道,HashMap中有几个重要的字段:
- 负载因子loadFactor,指哈希表在其容量自动增加之前可以达到多满的一种尺度
- 容量 capacity ,也就是当前table数组的长度
- 阈值threshold,用于判断是否需要调整HashMap的容量(rehashing),阈值=capacity * load factor
- 大小size,即HashMap存储的键值对数量
HashMap扩容的条件
关于扩容条件很多资料说的都是在size超过阈值时,就会触发扩容,以减少冲突的发生。
但我在这里告诉大家,这个说法是错误的或者是不准确的。我们直接看jdk1.7中HashMap的源代码:
void addEntry(int hash, K key, V value, int bucketIndex) {
//判断已经存在的Entry数量是否超过了实际可容纳量、当前节点是否发生hash碰撞。
if ((size >= threshold) && (null != table[bucketIndex])) {
//如果超过阈值并且即将发生hash碰撞,则进行resize
resize(2 * table.length);
//重新计算hash
hash = (null != key) ? hash(key) : 0;
//重新计算索引位置
bucketIndex = indexFor(hash, table.length);
}
//创建Entry节点对象
createEntry(hash, key, value, bucketIndex);
}
看到其中的if条件是,与,两个条件都满足才进行resize:
- size大于等于阈值
- 当前节点发生hash碰撞
所以如果只是size超过了阈值,而当前节点不发生碰撞的话,还是可以继续在原数组中存储数据的,因此就会出现下图的情况:
image.png
size=14 超过了 threshold=12 的阈值。
说明
经网友提醒该算法与jdk小版本有关,在jdk1.7.0_8中该逻辑已变更位如下
voidaddEntry(inthash,Kkey,Vvalue,intbucketIndex){
//获取指定bucketIndex索引处的Entry
Entry<K,V>e=table[bucketIndex];
//将新创建的Entry放入bucketIndex索引处,并让新的Entry指向原来的Entry
table[bucketIndex]=newEntry<K,V>(hash,key,value,e);
//如果Map中的key-value对的数量超过了极限
if(size++>=threshold)
//把table对象的长度扩充到原来的2倍。
resize(2*table.length);
}
网友评论