当前位置: 首页 > news >正文

深入解析Java HashMap的putVal方法

Java中的HashMap是我们在开发中经常使用的集合之一,它提供了基于哈希表的数据存储方式,使得对数据的插入、删除和查找操作都具有较高的效率。在本文中,我们将深入解析HashMap中的putVal方法,揭示其内部工作原理。通过对代码的逐行分析,我们不仅能够更好地理解HashMap的设计和实现,还能提高我们在实际开发中对HashMap的使用水平。

一、方法概述

putVal方法是HashMap中的核心方法之一,主要用于向HashMap中插入键值对。它的签名如下:

final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict)

参数说明:

  • hash:键的哈希值。
  • key:键。
  • value:值。
  • onlyIfAbsent:是否仅在键不存在时才插入。
  • evict:是否在插入后进行驱逐操作。

该方法的返回值是插入前与键关联的旧值,如果没有旧值则返回null

二、代码详细分析

下面我们将对putVal方法的每一部分进行详细的分析。

1. 初始化table
HashMap.Node<K, V>[] tab;
HashMap.Node<K, V> p;
int n, i;
if ((tab = table) == null || (n = tab.length) == 0)n = (tab = resize()).length;

在这段代码中,首先定义了局部变量tabpni。接着检查table是否为空或长度为0。如果是,则通过resize()方法进行初始化。这一步确保了HashMap的底层数组table已经被初始化且具有一定的容量。

2. 计算索引并插入新节点
if ((p = tab[i = (n - 1) & hash]) == null)tab[i] = newNode(hash, key, value, null);

这里通过 (n - 1) & hash 计算出键值对应该插入的索引位置,并检查该位置是否为空。如果为空,直接在该位置创建一个新的节点。值得注意的是,为什么使用 (n - 1) & hash 而不是 n & hash。因为 (n - 1) 能确保结果在 0n-1 之间,正好是数组的有效索引范围。

3. 处理哈希冲突
else {HashMap.Node<K, V> e;K k;if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))e = p;else if (p instanceof HashMap.TreeNode)e = ((HashMap.TreeNode<K, V>) p).putTreeVal(this, tab, hash, key, value);else {for (int binCount = 0; ; ++binCount) {if ((e = p.next) == null) {p.next = newNode(hash, key, value, null);if (binCount >= TREEIFY_THRESHOLD - 1)treeifyBin(tab, hash);break;}if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))break;p = e;}}if (e != null) {V oldValue = e.value;if (!onlyIfAbsent || oldValue == null)e.value = value;afterNodeAccess(e);return oldValue;}
}

这部分代码处理哈希冲突的情况。哈希冲突发生时,同一个索引位置可能会有多个节点。为了处理这些节点,HashMap使用了链表和红黑树两种数据结构。

  1. 覆盖旧值:首先检查当前节点的哈希值和键是否与待插入的键值对相同。如果相同,直接进行覆盖。
  2. 红黑树节点:如果当前节点是红黑树节点,通过putTreeVal方法处理。
  3. 链表节点:如果是链表节点,通过遍历链表找到适当的位置插入新节点。如果链表长度超过阈值(默认是8),会将链表转换为红黑树。
4. 维护结构修改计数和大小
++modCount;
if (++size > threshold)resize();
afterNodeInsertion(evict);
return null;

最后,更新modCount,表示HashMap的结构发生了变化。然后检查当前大小是否超过阈值,如果超过则进行扩容。扩容通过resize方法完成。最后调用afterNodeInsertion方法执行插入后的操作,返回null表示插入成功且没有旧值被覆盖。

三、关键细节与实现原理

1. 哈希函数

HashMap中,哈希函数的质量直接影响哈希表的性能。HashMap通过对键的哈希码进行二次扰动来减少哈希冲突,提高哈希分布的均匀性。

2. 链表与红黑树

HashMap最初使用链表来处理哈希冲突,但链表在极端情况下会退化为线性查找,性能较差。为了解决这个问题,Java 8引入了红黑树,当链表长度超过阈值时(默认是8),会将链表转换为红黑树,以提高查找效率。

3. 扩容机制

HashMap的扩容机制通过resize方法实现。每次扩容都会将容量扩大为原来的两倍,并重新计算所有元素的索引位置。扩容是一个代价较高的操作,因此HashMap会尽量延迟扩容,直到元素数量超过阈值。

四、优化与最佳实践

1. 初始容量设置

为了减少扩容次数,可以在创建HashMap时设置一个合理的初始容量。这样在插入大量元素时,可以减少扩容操作,提高性能。

2. 合理选择负载因子

HashMap的负载因子(默认是0.75)决定了扩容的阈值。负载因子越大,空间利用率越高,但哈希冲突的概率也越大。根据具体情况,可以选择合适的负载因子,以平衡空间利用率和性能。

3. 避免使用可变对象作为键

如果使用可变对象作为键,在对象状态变化后,哈希值可能会改变,导致无法正确查找到对应的值。因此,尽量使用不可变对象(如StringInteger等)作为键。

五、总结

通过对HashMapputVal方法的深入分析,我们了解了HashMap处理插入操作的详细过程,包括初始化、哈希冲突处理、扩容机制等。理解这些内部细节,不仅有助于我们更好地使用HashMap,还能在需要时对其进行优化,提升程序的性能。

在实际开发中,选择合适的数据结构和算法是至关重要的。HashMap作为Java中常用的集合类,其高效的实现和灵活的使用方式,使得它在众多应用场景中得到了广泛的应用。希望通过本文的分析,能够帮助读者更深入地理解HashMap的内部机制,提高编程技巧和代码质量。

相关文章:

深入解析Java HashMap的putVal方法

Java中的HashMap是我们在开发中经常使用的集合之一&#xff0c;它提供了基于哈希表的数据存储方式&#xff0c;使得对数据的插入、删除和查找操作都具有较高的效率。在本文中&#xff0c;我们将深入解析HashMap中的putVal方法&#xff0c;揭示其内部工作原理。通过对代码的逐行…...

使用智谱 GLM-4-9B 和 SiliconCloud 云服务快速构建一个编码类智能体应用

本篇文章我将介绍使用智谱 AI 最新开源的 GLM-4-9B 模型和 GenAI 云服务 SiliconCloud 快速构建一个 RAG 应用&#xff0c;首先我会详细介绍下 GLM-4-9B 模型的能力情况和开源限制&#xff0c;以及 SiliconCloud 的使用介绍&#xff0c;最后构建一个编码类智能体应用作为测试。…...

关于vue2 antd 碰到的问题总结下

1.关于vue2 antd 视图更新问题 1.一种强制更新 Vue2是通过用Object…defineProperty来设置数据的getter和setter实现对数据和以及视图改变的监听的。对于数组和对象这种引用类型来说&#xff0c;getter和setter无法检测到它们内部的变化。用这种 this.$set(this.form, "…...

常见的api:Runtime Object

一.Runtiem的成员方法 1.getRuntime() 当前系统的运行环境 2.exit 停止虚拟机 3.avaliableProcessors 获取Cpu线程的参数 4.maxMemory JVM能从系统中获取总内存大小(单位byte) 5.totalMemory JVM已经从系统中获取总内大小(单位byte) 6.freeMemory JVM剩余内存大小(…...

Linux守护进程揭秘-无声无息运行在后台

在Linux系统中&#xff0c;有一些特殊的进程悄无声息地运行在后台&#xff0c;如同坚实的基石支撑着整个系统的运转。它们就是众所周知的守护进程(Daemon)。本文将为你揭开守护进程的神秘面纱&#xff0c;探讨它们的本质特征、创建过程&#xff0c;以及如何重定向它们的输入输出…...

python-Bert(谷歌非官方产品)模型基础笔记0.1.096

python-bert模型基础笔记0.1.015 TODOLIST官网中的微调样例代码Bert模型的微调限制Bert的适合的场景Bert多语言和中文模型Bert模型两大类官方建议模型Bert模型中名字的含义Bert模型包含的文件Bert系列模型参数介绍微调与迁移学习区别Bert微调的方式Pre-training和Fine-tuning区…...

Linux的命令补全脚本

一 linux命令补全脚本 Linux的命令补全脚本是一个强大且高效的工具&#xff0c;它能够极大地提高用户在命令行界面的工作效率。这种脚本通过自动完成部分输入的命令或参数&#xff0c;帮助用户减少敲击键盘的次数并降低出错率。接下来将深入探讨其工作原理、安装方式以及如何自…...

前端 JS 经典:打印对象的 bug

1. 问题 相信这个 console 打印语句的 bug&#xff0c;其实小伙伴们是遇到过的&#xff0c;就是你有一个对象&#xff0c;通过 console&#xff0c;打印一次&#xff0c;然后经过一些处理&#xff0c;再通过 console 打印&#xff0c;发现两次打印的结果是一样的&#xff0c;第…...

大型语言模型简介

大型语言模型简介 大型语言模型 (LLM) 是一种深度学习算法&#xff0c;可以使用非常大的数据集识别、总结、翻译、预测和生成内容。 文章目录 大型语言模型简介什么是大型语言模型&#xff1f;为什么大型语言模型很重要&#xff1f;什么是大型语言模型示例&#xff1f;大型语…...

javaWeb4 Maven

Maven-管理和构建java项目的工具 基于POM的概念 1.依赖管理&#xff1a;管理项目依赖的jar包 &#xff0c;避免版本冲突 2.统一项目结构&#xff1a;比如统一eclipse IDEA等开发工具 3.项目构建&#xff1a;标准跨平台的自动化项目构建方式。有标准构建流程&#xff0c;能快速…...

eclipse连接后端mysql数据库并且查询

教学视频&#xff1a;https://www.bilibili.com/video/BV1mK4y157kE/?spm_id_from333.337.search-card.all.click&vd_source26e80390f500a7ceea611e29c7bcea38本人eclipse和up主不同的地方如下&#xff0c;右键项目名称->build path->configure build path->Libr…...

Windows mstsc

windows mstsc 局域网远程计算机192.168.0.113为例&#xff0c;远程控制命令mstsc...

百度/迅雷/夸克,网盘免费加速,已破!

哈喽&#xff0c;各位小伙伴们好&#xff0c;我是给大家带来各类黑科技与前沿资讯的小武。 之前给大家安利了百度网盘及迅雷的加速方法&#xff0c;详细方法及获取参考之前文章&#xff1a; 刚刚&#xff01;度盘、某雷已破&#xff01;速度50M/s&#xff01; 本次主要介绍夸…...

SOA的参考架构

1. 以服务为中心的企业集成架构 IBM的Websphere业务集成参考架构&#xff08;如图1所示&#xff0c;以下称参考架构&#xff09;是典型的以服务为中心的企业集成架构。 图1 IBM WebSphere业务集成参考架构 以服务为中心的企业集成采用“关注点分离&#xff08;Separation of Co…...

前端开发-表单和表格的区别

在前端开发中&#xff0c;表单&#xff08;Form&#xff09;和表格&#xff08;Table&#xff09;同样具有不同的用途和结构&#xff1a; 前端表单&#xff08;Form&#xff09;: 数据收集&#xff1a;表单用于收集用户输入的数据&#xff0c;如文本输入、选择选项等。用户交…...

Data Management Controls

Data Browsing and Analysis Data Grid 以标准表格或其他视图格式&#xff08;例如&#xff0c;带状网格、卡片、瓷砖&#xff09;显示数据。Vertical Grid 以表格形式显示数据&#xff0c;数据字段显示为行&#xff0c;记录显示为列。Pivot Grid 模拟微软Excel的枢轴表功…...

NextJs 数据篇 - 数据获取 | 缓存 | Server Actions

NextJs 数据篇 - 数据获取 | 缓存 | Server Actions 前言一. 数据获取 fetch1.1 缓存 caching① 服务端组件使用fetch② 路由处理器 GET 请求使用fetch 1.2 重新验证 revalidating① 基于时间的重新验证② 按需重新验证revalidatePathrevalidateTag 1.3 缓存的退出方式 二. Ser…...

腾讯开源人像照片生成视频模型V-Express

网址 https://github.com/tencent-ailab/V-Express 下面是github里的翻译&#xff1a; 在人像视频生成领域&#xff0c;使用单张图像生成人像视频变得越来越普遍。一种常见的方法是利用生成模型来增强受控发电的适配器。 但是&#xff0c;控制信号的强度可能会有所不同&…...

pytorch使用DataParallel并行化保存和加载模型(单卡、多卡各种情况讲解)

话不多说&#xff0c;直接进入正题。 &#xff01;&#xff01;&#xff01;不过要注意一点&#xff0c;本文保存模型采用的都是只保存模型参数的情况&#xff0c;而不是保存整个模型的情况。一定要看清楚再用啊&#xff01; 1 单卡训练&#xff0c;单卡加载 #保存模型 torc…...

PS初级|写在纸上的字怎么抠成透明背景?

前言 上一次咱们讲了很多很多很多的抠图教程&#xff0c;这次继续。。。最近有小伙伴问我&#xff1a;如果是写在纸上的字&#xff0c;要怎么把它抠成透明背景。 这个其实很简单&#xff0c;直接来说就是选择通道来抠。但有一点要注意的是&#xff0c;写在纸上的字&#xff0…...

C++初阶-list的底层

目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

UE5 学习系列(三)创建和移动物体

这篇博客是该系列的第三篇&#xff0c;是在之前两篇博客的基础上展开&#xff0c;主要介绍如何在操作界面中创建和拖动物体&#xff0c;这篇博客跟随的视频链接如下&#xff1a; B 站视频&#xff1a;s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

el-switch文字内置

el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)

笔记整理&#xff1a;刘治强&#xff0c;浙江大学硕士生&#xff0c;研究方向为知识图谱表示学习&#xff0c;大语言模型 论文链接&#xff1a;http://arxiv.org/abs/2407.16127 发表会议&#xff1a;ISWC 2024 1. 动机 传统的知识图谱补全&#xff08;KGC&#xff09;模型通过…...

【git】把本地更改提交远程新分支feature_g

创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...

C++.OpenGL (10/64)基础光照(Basic Lighting)

基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

【Java_EE】Spring MVC

目录 Spring Web MVC ​编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 ​编辑参数重命名 RequestParam ​编辑​编辑传递集合 RequestParam 传递JSON数据 ​编辑RequestBody ​…...