HashMap的扩容


当HashMap的size达到临界值capacity * loadFactor - 1时,HashMap会进行扩容,将自身容量增加一倍。
比如对未指定capacity和loadFactor的HashMap,缺省容量和负载因子分别为16和0.75,因此当map中存储的元素数量达到16 * 0.75 - 1即为11时,该map会将自身容量扩大到2 * 16 = 32。
在某些情况下,扩容耗费较多时间。如下面的代码

    public static void main()
    {
        HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
        for (int i = 0; i < 1200000; i += 3)
        {
            map.put(i, i + 1);
        }
    }

  JProfiler的统计信息如下,可以看到扩容的耗费在transfer方法上。

transfer功能是创建一个新的table并将map中现有的元素依次拷贝到新table中。上例中map中最终元素数为40万,扩容了16次,每次扩容需要transfer的数据数目分别是16 * 0.75 - 1 = 11, 32 * 0.75 - 1 = 23, 64 * 0.75 - 1 = 47, 128 * 0.75 - 1 = 71, ... ... , 262016 * 0.75 - 1 = 196511, 524032 * 0.75 - 1 = 393023


    为了在数据量较多时避免扩容,可以在创建HashMap时指定capacity。capacity的计算示意如下

如果map的最终元素数量落在如下的左面区间,那么HashMap不会扩容,否则会扩容。


        首先说明一下HashMap的构造函数决定容量的方式
        HashMap的构造函数自动会根据提供的initialCapacity寻找大于等于initialCapacity的并且是2的指数幂的最小数值。
        比如 new HashMap(17)new HashMap(31)创建的HashMap的容量都是32,但我们知道capacity为32的map扩容临界值为32 * 0.75 - 1 =  23,因此若最终map会放入31个元素,map会在放入第 23个元素的时候将容量从32扩大到64。
        创建HashMap时指定的capacity有两种计算方式,假定map容纳的元素数最终是数值m
那么

    方式一
    new HashMap(m * 4 / 3 + 3)

创建的map不会扩容
原因是对临界值m = 2^n * 0.75 - 1,m * 4 / 3 + 3结果2^n + 5/3取整为2^n + 1,而HashMap构造器的参数为2^n + 1时其capacity会是2^(n + 1),举例如下
22个元素对应的值22 * 4 / 3 + 3取整结果为32;23个元素对应的值22 * 4 / 3 + 3取整结果为33,new HashMap(33)创建的map最终容量是64.

    方式二

是直接找出大于m * 4 / 3 + 3的并且是2的指数幂的最小数值,比如m为17时,找出 17 * 4 / 3 + 3 = 25并且是2的指数幂的值为32,示例函数如下

int getMinCapacityNotResize(int targetEntrySize)
{
    if (targetEntrySize <= 0)
    {
        return 0;
    }
    double exponent = Math.log(targetEntrySize) / Math.log(2);
    double defaultInitCapacity = Math.pow(2, Math.ceil(exponent));
    double capacity = defaultInitCapacity;
    if (targetEntrySize >= defaultInitCapacity * 3 / 4 - 1)
    {
        capacity = defaultInitCapacity * 2;
    }
    return (int) capacity;
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值