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;
阅读 2.8k
1 个回答

虽然误差的绝对值在变大,但是比例却始终很小

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题