HashMap中的put方法执行流程(流程图)

news2025/7/27 9:21:16

1 put操作整体流程

HashMapput 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下:

  1. 初始判断与哈希计算
    • 首先,putVal 方法会检查当前的 table(也就是内部的 Node<K,V>[] 数组)是否为 null 或者长度为0。如果是,则会调用 resize() 方法进行初始化扩容,分配一个默认大小(通常是16)的数组空间。
    • 接下来,计算键 key 的哈希值。
      • 如果 keynull,它有一个特殊的处理逻辑,hash 会被置为0,并且通常会尝试将这个键值对放入 table[0] 的位置。
      • 如果 key 不为 null,则调用 key.hashCode() 获取原始哈希码,然后通过一个扰动函数 (h = key.hashCode()) ^ (h >>> 16) 对哈希码进行处理。这样做是为了让哈希值的高16位也参与到后续的索引计算中,使得哈希分布更均匀,减少哈希冲突。
  2. 计算数组索引 (定位哈希桶)
    • 使用经过扰动处理后的哈希值 hash(table.length - 1) 进行按位与 & 运算,即 i = (n - 1) & hash(其中 ntable 的长度)。这个操作等效于 hash % n,但位运算效率更高,前提是 n 必须是2的幂次方(HashMap 的容量设计保证了这一点)。这样就确定了该键值对应该存储在 table 数组的哪个索引位置(哪个哈希桶)。
  3. 处理指定索引位置的情况
    • p = table[i],检查该哈希桶 table[i] 是否为空:
      • 情况一:哈希桶为空 (p == null)
        • 如果该位置没有任何元素,说明没有发生哈希冲突。直接创建一个新的 Node(hash, key, value, null) 对象,并将其放入 table[i] 位置。
      • 情况二:哈希桶不为空 (p != null)
        • 这表示发生了哈希冲突,或者找到了一个已存在的键。
        • 首先检查头节点:判断桶的第一个节点 phash 值是否与新键的 hash 值相同,并且通过 key.equals(p.key)(或 key == p.key)判断键是否相等。
          • 如果键完全相同,说明是更新操作。将旧值 p.value 记录下来(用于 putVal 方法返回),然后用新的 value 替换 p.value。操作结束。
        • 如果头节点不是目标键,则检查节点类型
          • 如果 pTreeNode 类型 (即该桶已经转化为红黑树):
            • 调用红黑树的插入方法 p.putTreeVal(this, tab, hash, key, value) 将新的键值对插入到红黑树中。如果树中已存在相同的键,则更新其值。
          • 如果 p 是普通的 Node 类型 (即该桶是链表结构):
            • 遍历这个链表。在遍历过程中,使用 binCount 计数链表长度(从1开始,因为头节点已经算一个)。
            • 对于链表中的每个节点 e
              • 如果 e.hash == hash 并且 e.key.equals(key)(或 e.key == key),说明找到了相同的键,更新其值,操作结束。
            • 如果遍历到链表末尾(即 e.next = = null) 仍未找到相同的键:
              • 将新的键值对创建为一个新的 Node,并将其追加到链表的末尾(尾插法)。
              • 插入新节点后,检查链表长度 binCount(此时 binCount 是插入前的长度,所以判断 binCount + 1)是否达到了**树化阈值 **TREEIFY_THRESHOLD (默认为8)。
                • 如果达到了,并且当前 table 的长度 n 大于等于 MIN_TREEIFY_CAPACITY (默认为64),则调用 treeifyBin(tab, hash) 方法将这个链表转换为红黑树。
                • 如果 table 长度小于 MIN_TREEIFY_CAPACITY,则不会树化,而是会优先尝试 resize() 扩容。
            • 跳出链表遍历。
  4. 更新修改计数和大小
    • 如果成功插入了一个新的键值对(而不是更新已存在的键),modCount(记录 HashMap 结构修改次数的变量,用于迭代器的 fail-fast 机制)会自增。
    • sizeHashMap 中存储的键值对数量)会自增。
  5. 检查是否需要扩容
    • 在成功插入一个新节点后,会检查 ++size 是否大于 thresholdcapacity * loadFactor)。
    • 如果大于 threshold,则调用 resize() 方法对 HashMap 进行扩容。扩容通常会将容量翻倍,并重新计算所有元素在新表中的位置。
  6. 返回值
    • putVal 方法(以及 put 方法)会返回与指定键关联的前一个值,如果该键之前没有映射关系,则返回 null

总结一下 put 过程的关键点:

  • 计算哈希和索引。
  • 处理哈希桶:空桶直接放;非空桶则判断是更新、链表追加还是红黑树插入。
  • 链表过长且满足条件时会树化。
  • 插入新元素后检查是否需要扩容。
  • JDK 1.8 使用尾插法,并引入红黑树优化。

这个过程确保了 HashMap 在平均情况下能够提供 O(1) 的插入和查找性能,并在哈希冲突严重时通过红黑树将最坏情况下的性能维持在 O(logN)。

流程图

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2407361.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2025季度云服务器排行榜

在全球云服务器市场&#xff0c;各厂商的排名和地位并非一成不变&#xff0c;而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势&#xff0c;对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析&#xff1a; 一、全球“三巨头”…

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求&#xff0c;并检查收到的响应。它以以下模式之一…

用机器学习破解新能源领域的“弃风”难题

音乐发烧友深有体会&#xff0c;玩音乐的本质就是玩电网。火电声音偏暖&#xff0c;水电偏冷&#xff0c;风电偏空旷。至于太阳能发的电&#xff0c;则略显朦胧和单薄。 不知你是否有感觉&#xff0c;近两年家里的音响声音越来越冷&#xff0c;听起来越来越单薄&#xff1f; —…

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…

中医有效性探讨

文章目录 西医是如何发展到以生物化学为药理基础的现代医学&#xff1f;传统医学奠基期&#xff08;远古 - 17 世纪&#xff09;近代医学转型期&#xff08;17 世纪 - 19 世纪末&#xff09;​现代医学成熟期&#xff08;20世纪至今&#xff09; 中医的源远流长和一脉相承远古至…

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比

在机器学习的回归分析中&#xff0c;损失函数的选择对模型性能具有决定性影响。均方误差&#xff08;MSE&#xff09;作为经典的损失函数&#xff0c;在处理干净数据时表现优异&#xff0c;但在面对包含异常值的噪声数据时&#xff0c;其对大误差的二次惩罚机制往往导致模型参数…

HDFS分布式存储 zookeeper

hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架&#xff0c;允许使用简单的变成模型跨计算机对大型集群进行分布式处理&#xff08;1.海量的数据存储 2.海量数据的计算&#xff09;Hadoop核心组件 hdfs&#xff08;分布式文件存储系统&#xff09;&a…

佰力博科技与您探讨热释电测量的几种方法

热释电的测量主要涉及热释电系数的测定&#xff0c;这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中&#xff0c;积分电荷法最为常用&#xff0c;其原理是通过测量在电容器上积累的热释电电荷&#xff0c;从而确定热释电系数…

HarmonyOS运动开发:如何用mpchart绘制运动配速图表

##鸿蒙核心技术##运动开发##Sensor Service Kit&#xff08;传感器服务&#xff09;# 前言 在运动类应用中&#xff0c;运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据&#xff0c;如配速、距离、卡路里消耗等&#xff0c;用户可以更清晰…

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)

船舶制造装配管理现状&#xff1a;装配工作依赖人工经验&#xff0c;装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书&#xff0c;但在实际执行中&#xff0c;工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…

算法岗面试经验分享-大模型篇

文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer &#xff08;1&#xff09;资源 论文&a…

技术栈RabbitMq的介绍和使用

目录 1. 什么是消息队列&#xff1f;2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)

前言&#xff1a; 最近在做行为检测相关的模型&#xff0c;用的是时空图卷积网络&#xff08;STGCN&#xff09;&#xff0c;但原有kinetic-400数据集数据质量较低&#xff0c;需要进行细粒度的标注&#xff0c;同时粗略搜了下已有开源工具基本都集中于图像分割这块&#xff0c…

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题

分区配置 (ptab.json) img 属性介绍&#xff1a; img 属性指定分区存放的 image 名称&#xff0c;指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件&#xff0c;则以 proj_name:binary_name 格式指定文件名&#xff0c; proj_name 为工程 名&…

【7色560页】职场可视化逻辑图高级数据分析PPT模版

7种色调职场工作汇报PPT&#xff0c;橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版&#xff1a;职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1

AI病理诊断七剑下天山,医疗未来触手可及

一、病理诊断困局&#xff1a;刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断"&#xff0c;医生需通过显微镜观察组织切片&#xff0c;在细胞迷宫中捕捉癌变信号。某省病理质控报告显示&#xff0c;基层医院误诊率达12%-15%&#xff0c;专家会诊…

Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)

Aspose.PDF 限制绕过方案&#xff1a;Java 字节码技术实战分享&#xff08;仅供学习&#xff09; 一、Aspose.PDF 简介二、说明&#xff08;⚠️仅供学习与研究使用&#xff09;三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…

论文笔记——相干体技术在裂缝预测中的应用研究

目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术&#xff1a;基于互相关的相干体技术&#xff08;Correlation&#xff09;第二代相干体技术&#xff1a;基于相似的相干体技术&#xff08;Semblance&#xff09;基于多道相似的相干体…

网站指纹识别

网站指纹识别 网站的最基本组成&#xff1a;服务器&#xff08;操作系统&#xff09;、中间件&#xff08;web容器&#xff09;、脚本语言、数据厍 为什么要了解这些&#xff1f;举个例子&#xff1a;发现了一个文件读取漏洞&#xff0c;我们需要读/etc/passwd&#xff0c;如…

回溯算法学习

一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…