JDK8中的HashMap的resize()方法,如果修改了load factor,可能会出现误差?
问题描述
JDK8中的JDK8中的HashMap的resize()方法,如果修改了loadFactor,在之后resize的时候可能会出现误差。
按理说,threshold应该一直等于 capacity * loadFactor,但是resize()方法中,当capacity大于16之后,在把capacity变为原来的两倍的同时,把threshold也直接变为了原来的两倍了。这种方式在loadFactor为默认值,也就是0.75的时候是没有问题的。但是如果自己调整了loadFactor,比如把loadFactor改了0.70,那么这种扩容方式就会出现误差。
如图
我已经通过调试测试验证了以上数据。想问一下,有没有人知道类的设计者为什么没有考虑这种情况,还是有意忽略了?
相关代码
resize()函数部分源代码
// 进入这个方法的前提代表size已经大于threshold了final Node<K,V>[] resize() {
Node<K,V>[] oldTab = table;
int oldCap = (oldTab == null) ? 0 : oldTab.length;
int oldThr = threshold;
int newCap, newThr = 0;
if (oldCap > 0) { // oldCap大于0,说明table长度不是0,不是第一次resize()
if (oldCap >= MAXIMUM_CAPACITY) { // oldCap存的是table长度,就是扩容前的容量,大于等于最大capacity,不再扩容
threshold = Integer.MAX_VALUE; // 把threshold设置为整形的最大值,这样之后就不会再进入resize()方法了
return oldTab;
}
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && // 需满足扩容之后仍小于最大capacity限制
oldCap >= DEFAULT_INITIAL_CAPACITY) // 需满足旧的容量大于默认初始容量
newThr = oldThr << 1; // double threshold // 产生误差的地方,因为这个时候旧的threshold直接乘2,
// 不再是新容量乘以负载因子了,误差会不断累积
}
// 只有初始化的时候才会进入
else if (oldThr > 0) // initial capacity was placed in threshold 这里只针对显式初始化了initial capacity的情形,此时
// oldCap等于零,说明oldTab为null。oldThr存的是初始化的threshold,也就是initial capacity
newCap = oldThr; // 这里就相当于把newCap赋值为initial capacity了
// 没有显式指定initial capacity,或者显式制定了initial capacity为0,都使用默认initial capacity
else { // zero initial threshold signifies using defaults,
newCap = DEFAULT_INITIAL_CAPACITY;
newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
}
// 指定的initial capacity小于默认capacity时候的前几次resize()
// 所有情形最后一次resize()
if (newThr == 0) {
float ft = (float)newCap * loadFactor;
newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
(int)ft : Integer.MAX_VALUE);
}
threshold = newThr;
回答:
虽然误差的绝对值在变大,但是比例却始终很小
以上是 JDK8中的HashMap的resize()方法,如果修改了load factor,可能会出现误差? 的全部内容, 来源链接: utcz.com/a/166308.html