浅析HashMap(jdk11)【1】初始化部分(静态域、实例域、构造函数、扩容)

看《Java并发编程的艺术》到第六章了,讲并发框架的,里面提到了使用HashMap会出现循环引用的情况,搜了下,HashMap1.7在扩容时采用头插法,会成环,导致多线程的场景下容易出现死循环;然后又听说1.8的红黑树也会出现成环的问题…就有点好奇hashmap内部是咋样的了,
俺这边没有jdk8,7的环境。就看看11的吧(虽然1.8那个bug我是一直没复现出来)

先看一下UML吧,好像是有点复杂的亚子,一点一点看吧
在这里插入图片描述

静态属性

在这里插入图片描述
从上到下解释

  • 第一个不用解释吧,序列号
  • DEFAULT_INITIAL_CAPACITY:初始筒容量,为16
  • MAXIMUM_CAPACITY:最大容量,2^30次方,因为这是int类型最大的2的幂次方了。(至于为啥要保持2的幂次方后面再解释)
  • DEFAULT_LOAD_FACTOR:负载系数,当使用容量和总容量的比值超过该值时,便需要扩容了。默认为0.75,可以自己设置,选0.75是一个空间与时间的平衡。
  • TREEIFY_THRESHOLD:超过该值就会从链表转换为红黑树,为8这个是根据泊松分布得来的,因为默认调整值为0.75,一个良好的哈希分布函数,桶中Node的分布频率满足泊松分布,为8的可能性已经很小很小了,如果为8了,说明这是一种比较极端的情况(正常情况下扩容就完事了),Map中的分布可能不是很良好,这时便需要将链表转换为红黑树,以空间换时间(TreeNode所占内存是链表节点的两倍)。
  • UNTREEIFY_THRESHOLD:当节点低于这种情况时,红黑树转换为链表,为6.
  • MIN_TREEIFY_CAPACITY:最小得满足这个桶数量才能使链表转换为树,为了防止转换为树和扩容的冲突。64

类属性

在这里插入图片描述

  • table:桶,长度为2的幂次方
  • entrySet:键值对组成的set。
  • size:当前key-value节点数
  • modCount:如果在对节点进行修改的时候这个值就会自增,如果这时候正好有线程在遍历操作(或者类似的操作),这时就会抛ConcurrentModificationException
  • threshold:当前最大容量
  • loadFactor:负载因子

初始化

有仨构造函数
1.空参 2.含初始容量 3.带初始容量和设置的负载参数。4.传入一个Map
前两个都是调用第三个实现的,那我们直接看第三个吧。
就是判断下是否非法(长度位负数)是则抛异常
如果超出允许的最大值了则设为最大值
然后再将真正的容量设为initialCapacity的最接近的大于或者等于2的幂次方

 public HashMap(int initialCapacity, float loadFactor) {
   
        //初始容量小于0,那还装啥,抛异常
        if (initialCapacity < 0)
            throw new IllegalArgumentException
            ("Illegal initial capacity: " + initialCapacity);
        //如果设置的初始容量太大了设置为允许的最大值(2^30)
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        //负载参数不能小于0
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);
        //将合法的负载参数赋予给类变量
        this.loadFactor = loadFactor;
        //将初始化容量转换为二次幂
        //里面用了个Integer.numberOfLeadingZeros方法
        //来求(31-传入数字的二进制最高位数)(x)
        //【如果传入为负数返回的就会是个负数了】
        //再将-1>>>x位即得到最接近且大于等于传入数字的2的幂次方
        this.threshold = tableSizeFor(initialCapacity);
    }

第四个构造函数
将一个map作为参数传入,将它们存入本map中。

public HashMap(Map<? extends K, ? extends V> m) {
   
        this.loadFactor = DEFAULT_LOAD_FACTOR;
        //将m转化为键值对插入map
        putMapEntries(m
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值