HashMap是如何 put 并自动扩容?

插入:

默认空初始化方式,首次插入数据

  1. 对 HashMap 初始化(不指定长度),使用 put 方法将数据进行插入:
     HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
     objectObjectHashMap.put("1","12");
    
  2. 我们进入到 put 方法中:
  3. 我们可以看到又调用了 putVal 方法,第一个参数对 key 又进行了 hash 操作,我们进入 hash 方法中, key = "1"
    1. 此时,运用三元运算对 key 进行判空,如果不为空,将获取 key 的 hashCode 编码并赋值给 h
    2. 将 h 无符号向右移 16 位,并和 key 的 hashCode 进行 异或(相同为 0,不同为 1) 操作
  4. 此时调用 putValue 方法,参数为:
  5. 进入 putVlue 方法:
    1. 此时方法中的参数为:
    2. 我们进行第一个 if 判断:
      1. 由于我们是第一次进入,初始数组 table 未初始化所以为 空,长度也为 0
      2. 进入 if 方法块中,此时调用了 resize 方法对数组进行初始化
    3. 我们进入 resize() 方法:
      1. 在当前方法中变量信息如下:
      2. 第一个 if 判断,oldCap 旧数组长度为 0,不符合
      3. 第二个 if 判断,oldThr 旧阈值为 0 ,也不符合
      4. 直接进入 else 代码块中:
      5. 将新数组长度和新阈值进行赋值操作:
      6. 继续判断 newThr 新阈值是否为0 ,此时 newThr = 14 不为 0,则继续向下执行
      7. 此时要创建默认长度的数组,并赋值给类变量
      8. 赋值完成后进行 if 判断 oldTab 是否不为空,此时 oldTab 指向的 table 是刚刚开辟出的新数组,不为空,则进入代码块:
      9. for 循环中的第一个 if 判断数组中的元素是否不为空,此时的数组没有元素,判断不成立,直接跳出 for 循环
      10. 最后将新数组进行返回
    4. 回到 putVal 方法中:
      1. 此时将数据进行赋值:
      2. 下面再判断 数组中最后一个元素与 hash 值做与操作是否为空:因为数组中没有元素取出的值为 null 所以 最后结果也为  null,则进入代码块:
      3. 此时调用 newNode 方法新建一个节点并赋值给数组的最后一个元素。我们进入 newNode 方法:
      4. 该方法创建一个新节点并返回,返回后的数组如图所示:
      5. 继续向下执行为:
      6. 将 modCount 和 size 都相加之后,再进行 IF 判断,此时类中的数据为:
      7. 此时 IF 判断为:当某一个链表长度大于 8 时,则进行扩容操作
      8.  否则直接进入 afterNodeInsertion 方法中:
        1. 此方法实现 LRU 算法,可不看
      9. 最后返回空值

     多次插入数据后:      

  1. 直接进入 putVal 方法:
    1. 此时 前面的两个 IF 判断都不成立,直接进入 else 代码块:
    2. 第一个 IF 判断为:当 hash 值和 key 都相等时,将 旧节点 p 赋值给 新节点 e,跳出当前 IF 判断, 程序向下执行:
    3. 此时 IF 判断成立,将旧节点的 Value 值进行保存,将新节点的值进行覆盖,并返回旧的 Value 值
    4. 第二个 IF 判断为:当 hash 值相等,key 值不相等时,就会进入第二层判断
      1. 当前节点是否是树结构,如果是树结构则将此节点插入到红黑树中
    5. 如果上面两种都不符合的时,此时 hash 值下的节点是个链表结构,进入到 else 中:
      1. 首先用 for 进行无限遍历次链表
      2. 当 p 的下一个节点为 空 时
        1. 使用尾插法,将节点插入到链表末端
        2. 再插入完毕后,判断当前链表如果大于等于 7,则把链表转化为树结构(树化桶)
      3. 当遍历过程中,找到对应的 key 值时,跳出循环,将旧节点进行替换。
  2. 我们看 treefiyBin (树化桶) 方法:
    1. 第一个 IF 判断为:当前数组为空,或者当前数组长度小于 64 时,进行 resize 扩容操作,而不是树化操作
    2. 当数组大于 64 时,进行树化操作

总结:

  1. 数组扩容情况:
    1. 当数组长度大于阈值(0.75倍)时,数组则会扩容 2 倍
    2. 当某一个 hash 值下的链表长度大于 8 时,并且数组长度小于 64 时,也会进行扩容
  2. 链表转树情况:
    1. 当某一 hash 值下的链表长度大于 8,数组长度 等于 64时,则会进行链表转为树操作
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值