解剖HashMap的put <四> jdk1.8

发布于:2025-08-15 ⋅ 阅读:(16) ⋅ 点赞:(0)

第四步是 “插入或更新元素”—— 这是实际执行数据存储的步骤,根据第三步(处理哈希冲突)的判断结果,要么更新已有 Key 的 value,要么将新 Key-value 插入到对应的数据结构中。


第四步的核心操作:两种场景的处理

经过第三步的冲突处理后,会出现两种明确的结果:“找到相同的 Key” 或 “确认是新 Key”,第四步针对这两种场景分别操作。

场景 1:找到相同的 Key(需要更新 value)

如果在第三步的遍历中(无论是链表还是红黑树),发现了与新 Key “相同” 的节点(哈希值相同且equals()返回 true),则执行更新操作

  • 用新的 value 覆盖该节点的旧 value;
  • 返回被覆盖的旧 value(这也是put方法的返回值逻辑:如果 Key 已存在,返回旧值;否则返回 null)。

举例
HashMap 中已有 ("name", "张三"),现在调用put("name", "李四")

  • 第三步会找到 “name” 对应的节点;
  • 第四步将该节点的 value 从 “张三” 更新为 “李四”;
  • put方法返回 “张三”。
场景 2:确认是新 Key(需要插入新节点)

如果第三步遍历完所有节点后,未发现相同的 Key,则确认是新 Key,执行插入操作

  1. 创建新节点:根据当前桶的结构,创建对应的节点(链表节点Node或红黑树节点TreeNode)。
  2. 插入节点
    • 若桶是链表:将新节点插入链表尾部(尾插法,JDK 1.8 特性);
    • 若桶是红黑树:按照红黑树的插入规则将新节点加入树中,并维持树的平衡。
  3. 更新元素计数:HashMap 的元素数量size加 1(size++),表示新增了一个键值对。

举例
HashMap 中已有 ("name", "张三"),现在调用put("age", 20)

  • 假设 “age” 计算出的索引与 “name” 不同(无冲突),直接在对应桶插入新节点;
  • 若有冲突(索引相同),则在链表尾部或红黑树中插入 “age” 节点;
  • size从 1 变为 2,put方法返回 null。

第四步的核心目标

  1. 保证数据准确性:对于重复 Key,通过更新 value 维持 “Key 唯一” 的特性;对于新 Key,正确存储到对应的数据结构中。
  2. 维护内部状态:通过更新size计数,为后续的扩容判断(第五步)提供依据。

与其他步骤的关联

  • 依赖第三步的结果:只有明确是 “更新” 还是 “插入”,第四步才能执行具体操作;
  • 为第五步铺垫:插入新节点后size增加,才需要判断是否超过阈值(threshold),进而触发扩容。

归纳

第四步是 HashMap 完成数据存储的 “落地” 步骤:通过 “更新” 或 “插入” 两种操作,将键值对最终存入容器中,同时维护 HashMap 的核心状态(size和数据结构完整性)。这一步完成后,就会进入最后一步 —— 判断是否需要扩容。


网站公告

今日签到

点亮在社区的每一天
去签到