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

相关推荐
白杨尚青3 小时前
C++进阶篇(二):多态——虚函数、重写、虚函数表与三个经典坑(附完整代码仓库)
开发语言·c++·多态·虚函数·重写·动态绑定
考虑考虑9 小时前
JDK26中的Map.ofLazy
java·后端·java ee
鶴哥只手遮天12 小时前
Spring AI 2.0.1 深度解析-第 14 章 MCP 服务端(上):注解式实现与工具来源
java·人工智能·开源
鶴哥只手遮天13 小时前
Spring AI 2.0.1 深度解析-第 15 章 MCP 服务端(下):三种协议形态、Streamable 传输与状态管理
java·人工智能·开源
鶴哥只手遮天13 小时前
Spring AI 2.0.1 深度解析-第 16 章 向量存储(上):`VectorStore` 接口体系、`BatchingStrategy`
java·人工智能·开源
鶴哥只手遮天13 小时前
Spring AI 2.0.1 深度解析-第 12 章 工具循环的流式形态、Usage 累加与扩展体系
java·人工智能·开源
鶴哥只手遮天13 小时前
Spring AI 2.0.1 深度解析-第 23 章 模型供应商实现:从 `OpenAiSetup` 到 Bedrock
java·人工智能·开源
鶴哥只手遮天13 小时前
Spring AI 2.0.1 深度解析-第 06 章 内置 Advisor 全景:13 个实现逐个剖到源码级
java·人工智能·开源
鶴哥只手遮天13 小时前
Spring AI 2.0.1 深度解析-第 03 章 消息体系与 Prompt:不可变模型、`ChatOptions` 与模板渲染
java·人工智能·开源