HashMap的容量与扩容

阅读JDK源码是提高我们技术很好的途径,其中HashMap的设计是非常优秀的,但是其中定义了许多变量,让人头昏目眩,那么这些变量都是什么意思呢

HashMap中的变量

本篇文章主要关注的字段是DEFAULT_INITIAL_CAPACITY、DEFAULT_LOAD_FACTOR、size、loadFactor、threshold、capacity

  • DEFAULT_INITIAL_CAPACITY:容器的默认初始容量,16

  • DEFAULT_LOAD_FACTOR:容器的默认加载因子,0.75f

  • size:当前容器已经放置了多少元素

  • loadFactor:加载因子用来衡量该容器满的程度,也就是说该集合可以放多少元素与这个字段有直接关系。

  • threshold:容器扩容阀值,当集合存放元素数量超过这个值之后,HashMap会扩容。(threshold = capacity * loadFactor)

  • capacity:容量,当前集合最多可以存放多少元素(通常不会放满)

size和capacity

初始化一个HashMap集合,他的默认容量。放置元素后,size数值变化。下面是测试代码:

/* 查看map的初始容量,和当前存放元素数量*/
    
        HashMap<String, String> map = new HashMap<String, String>();
        map.put("sxl", "sxl");

        Class<? extends HashMap> mapClass = map.getClass();
        Method capacity = mapClass.getDeclaredMethod("capacity");
        capacity.setAccessible(true);
        int capacity2 = (int) capacity.invoke(map);

        System.out.println("map capacity = " + capacity2);

        Field size = mapClass.getDeclaredField("size");
        size.setAccessible(true);
        int size2 = (int) size.get(map);
        System.out.println("map size = " + size2);
        // mt:为什么设置HashMap的初始容量是16    d:主要一个好处就是使用按位与替换取模,提高hash效率
    

输出结果

map capacity = 16
map size = 1

除了默认的初始化容量,我们可以自定义容量吗?可以的,但是capacity只能是2的倍数(为了计算key的数组下标时优化取模计算为&位运算)

HashMap还为我们提供了自定义初始容量的构造器:public HashMap(int initialCapacity)

测试代码

HashMap<String, String> map1 = new HashMap<String, String>(1);
        HashMap<String, String> map2 = new HashMap<String, String>(7);
        HashMap<String, String> map3 = new HashMap<String, String>(10);

        Class<? extends HashMap> mapClass = map1.getClass();
        Method capacity = mapClass.getDeclaredMethod("capacity");
        capacity.setAccessible(true);

        System.out.println("map1 capacity = " + (int) capacity.invoke(map1));
        System.out.println("map2 capacity = " + (int) capacity.invoke(map2));
        System.out.println("map3 capacity = " + (int) capacity.invoke(map3));

        // map的容量扩充采用按位与
        // 创建HashMap时尽量指定初始容量,尤其是知道map中会存放多少元素时

输出结果

map1 capacity = 1
map2 capacity = 8
map3 capacity = 16

loadFactor和threshold

当集合中存放元素超过threshold阈值之后,Hashmap会扩容,且扩容是2的n次幂。这样扩容的目的是保持capacity是2的倍数,在计算key的数组下标时优化取模为&位运算,直接与内存交互避免二进制与十进制转换,提交运算效率。

下面是Map扩容的测试代码

        // 先往map中放12个KV
        HashMap<String, String> map = new HashMap<>();
        for (int i = 0; i < 12; i++) {
            map.put("sxl"+i, "sxl");
        }
        
        Class<? extends HashMap> mapClass = map.getClass();
        // 打印capacity
        Method capacity = mapClass.getDeclaredMethod("capacity");
        capacity.setAccessible(true);
        System.out.println("map capacity = " + capacity.invoke(map));
        // 打印size
        Field size = mapClass.getDeclaredField("size");
        size.setAccessible(true);
        System.out.println("map size =" + size.get(map));
        // 打印loadFactor
        Field loadFactor = mapClass.getDeclaredField("loadFactor");
        loadFactor.setAccessible(true);
        System.out.println("map localFactor =" + loadFactor.get(map));
        // 打印threshold
        Field threshold = mapClass.getDeclaredField("threshold");
        threshold.setAccessible(true);
        System.out.println("map threshold =" + threshold.get(map));

        System.out.println();

        // 上面打印了防止12个元素,几个容量相关元素数值,再放map中放一个元素查看数值
        map.put("sxl13","sxl");
        System.out.println("map capacity = " + capacity.invoke(map));
        System.out.println("map size =" + size.get(map));
        System.out.println("map localFactor =" + loadFactor.get(map));
        System.out.println("map threshold =" + threshold.get(map));

        // HashMap的KV个数超出threshold时会进行扩容 threshold = (loadFactor * capacity)

输出结果

map capacity = 16
map size =12
map localFactor =0.75
map threshold =12

map capacity = 32
map size =13
map localFactor =0.75
map threshold =24

通过上面这个测试,可以证明HashMap的KV个数超出threshold时会进行扩容 threshold = (loadFactor * capacity)

总结

HashMap的容量和扩容主要涉及到size、capacity、loadFctor、threshold几个参数,其中size是map已经存储KV对的数量。capacity是map最大可以存放的数量。loadFacotr用来控制map放满的程度,可以自己设置但是一般使用默认的即可(0.75即3/4,这个值还有一个优点就是loadFactor*capacity一直是整数)。当map中KV对的数量超过threshold时map会扩容,扩容为旧容量的2倍。


业精于勤,荒于嬉;行成于思,毁于随。

Hppay ending~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值