HashMap扩容全流程

扩容时机:元素数量 > 容量 × 负载因子

调用resize()进行扩容

注意:新建 HashMap 不初始化数组,第一次 put 时,resize 才会创建数组(懒加载)。

意思就是:

即使不扩容,而是第一次创建数组后第一次 put,也是用 resize 实现的

resize全流程

1.判断旧数组是否存在

  • 旧数组为null(首次 put):旧容量 = 0,新容量 = 默认 16,新阈值 = 16×0.75=12
  • 旧数组不为 null:
    • 旧容量oldCap左移一位 newCap = oldCap << 1(翻倍)
    • 旧阈值oldThr左移一位 newThr = oldThr <<1
    • 上限:最大容量MAX_CAPACITY = 1 << 30,超过就不再扩容,阈值设为Integer.MAX_VALUE

1.旧容量即原数组长度;旧阈值即0.75原倍数组长度

2.<< 是左移运算符:二进制整体往左挪 1 位,右边补 0,等价 乘以 2,这也是为什么每次扩容都是加倍

3.MAX_CAPACITY = 1 << 30 1 << 30:1 左移 30 位 = 2³⁰ = 1073741824,HashMap 允许数组最大长度就是这个。

2.创建新数组

Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];

1.Node<K,V>是这里面的节点类

2.把table引用指向新数组(地址),旧数组保留临时引用oldTab,准备迁移元素

3.不应该是Node<K,V>\[\] newTab =new Node<K,V>newCap;吗

语法上想表达的意思是对的,但是 Java 不允许直接这样写!(反正有ai了现在无所谓)

3. 遍历旧数组,迁移每一个桶(核心)

用遍历其中每个位置下的链表吗?看下面每一种情况你就知道了

  • 情况①:oldTab[i] == null → 直接跳过,无元素
  • 情况②:当前桶只有单个节点(无链表 / 红黑树)
    • 直接计算新下标:newIndex = hash & (newCap -1),放到新数组对应位置
  • 情况③:桶内是链表 (多个 Node,还没转红黑树) 尾插法!!
    • jdk8不再重新hash

我们把在原位置的叫做低位,位置改变的叫做高位

  • 情况④:桶内是红黑树

调用 split() 方法拆分红黑树,同样按 hash & oldCap 分成低位、高位两组。

补充:

因为扩容后放的位置是(table - 1)& hashCode

而hashCode是由key根据固定公式求的,所以不会变

并且16=>二进制:10000 => -1 = 01111

扩容后: 100000 => -1 = 011111

与运算举例子(不同hash值举例):

eg1. 00101 => 分别和新老table-1值作与运算 => 00101、00101

eg2. 10101 => 分别和新老table-1值作与运算 => 00101、10101

eg3. 01100 => 分别和新老table-1值作与运算 => 01100、01100

eg4. 11100 => 分别和新老table-1值作与运算 => 01100、11100

扩容了,但是做与运算需要数组长度 - 1,所以总的来说相当于前面多了一位 1,现在要和 hashcode 做与运算,只需要看第五位不就行了,第五位扩容前为零,扩容后和原 hashcode 值相同 得到扩容后的下标

(五是因为这里仅仅拿16 -> 32 举例)

所以就是 hashcode 的第五位,如果是 0,那么下标不变(rehash后还在原位置 ),如果是 1,则下标改变(新下标 = 原下标 i + oldCap )自己多想一下为什么+ oldCap

相关推荐
xiaoye-duck24 分钟前
《C++ 项目:手写大模型接入 SDK》LLMManager架构设计与实现
开发语言·网络·c++·语言模型
一条大祥脚1 小时前
CuTe 与 CuTe DSL:从 C++ 模板元编程到 Python DSL 的 GPU 编程演进
开发语言·c++·python·cutlass·cute·cute dsl
学长毕设1 小时前
基于SpringBoot的野生动物公益保护平台设计与实现-附源码
java·spring boot·后端
FRing032 小时前
vue2干货总结8(路由模块封装、router-link、声明式导航、路由重定向、编程式导航)
开发语言·前端·vue.js·vue2
旖旎夜光2 小时前
【C++ 基础入门】C++ 多态(上):虚函数、重写、override/final 与抽象类
开发语言·c++·笔记·学习
SL_staff2 小时前
离散制造排程破局:JVS-APS 四步闭环落地实践(开发者视角)
java·产品·全栈
这个昵称不容易2 小时前
SpringBoot 美容院管理系统:232个Java文件315个接口,5套角色从预约到发货一整条链路
java·springboot·毕设
starzy19902 小时前
深入理解Scala嵌套函数:作用域封装之道
开发语言·scala
Sakura_j_h_2 小时前
从零写一个 MCP stdio Server:用 Python 校验博客文章格式
开发语言·python·自动化·ai工具·mcp·json-rpc
装不满的克莱因瓶3 小时前
【SpringAI Alibaba】ReactAgent记忆管理MessageTrimmingHook与MessageDeletionHook
java·人工智能·ai·ai编程·springai·springaialibaba