HashMap源码分析小结
HashMap相关问题
HashMap实现原理
HashMap是以键值对的形式存储数据,内部是通过数组+链表结构实现,在1.7之后的版本,链表结构可以升级为红黑树,提高查询效率
- key和value都支持为null;key为null时hash值是0,取模后也是0 ,也是就是会存放在数组第一个链表中
HashMap的put、get、remove过程
put过程:
-
先根据key值计算Hash值
-
再根据hash值与数组长度进行取模运算,计算出要落在数组哪个位置上
-
接着判断数组是否为空,为空的话对数组进行初始化,默认数组容量是16
-
然后判断该数组位置是否已经存在元素,如果不存在则直接创建Node结点放入数组对应位置
-
如果存在则继续判断是否是红黑树,如果是红黑树则在红黑树中创建或者更新Node结点
-
如果是链表结构,则先插入元素,然后判断链表中元素个数是否已经到达阈值8个,如果到达了,并且数组容量大于64个,则将当前链表升级为红黑树结构,如果不足64则进行一次扩容
-
在扩容时,红黑树会进行拆分,拆分过程中会判断红黑树中结点是否少于阈值6个,如果是的话变回链表结构
-
remove元素时判断根节点和左右子节点是否为null来决定是否转回链表结构,而没有根据阈值6来判断
-
-
最后插入完元素后,会判断当前元素总的个数是否达到阈值,默认是数组容量的3/4,如果达到了则进行扩容
- 3/4是根据空间和时间综合判定的,如果设置过小,则扩容频繁,如果设置过大,则hash冲突概率增加,查找效率更低
get过程:
-
先通过key计算hash值,然后与数组长度取模运算确定在数组中的位置
-
然后判断数组中对应元素key值是否相同,相同则返回该结点的value值
-
接着判断是否是红黑树,如果是的话从红黑树中查找该key对应结点
-
如果是链表则遍历链表中每一个元素找到key值相同的Node结点并返回value值
remove过程:
-
remove过程和查找差不多,也是先计算hash值,取模计算出数组位置,然后判断是否红黑树等等,找到元素后从原来位置删除
-
从红黑树中删除之后,会判断根节点以及其左右结点是否为空来决定要不要转回链表结构
容量转为2的n次幂
-
int n = cap - 1; n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16;
-
现将设置的容量减1,然后不断进行右移和或运算,目的是将低位上的数都转为1(0000 1111);最后再+1,形成(0001 0000)这种结构,结果必然是2的n次方
Hash算法和Hash冲突问题
-
(key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16)
-
key可以为null
-
hash值的计算:key的hash值与它的高16位右移后进行异或运算,目的是为了降低低16位相同的概率,从而减少hash碰撞
-
这是因为跟数组长度-1进行与运算时,数组长度-1的高位基本都是0,进行与运算后结果也是0 ,如果两个数高位不同,低位相同,就会导致计算结果一致,发生hash碰撞;
-
所以需要降低低位相同的概率,就能减少hash碰撞
-
-
为什么进行异或运算,而不是与运算或者或等其他运算?
-
因为如果进行与运算,会导致结果趋向于0更多
-
进行或运算,结果趋向于1更多
-
只有进行异或运算,结果0和1的个数会趋于一样多,这样结果随机性就更大,hash碰撞概率就小很多
-
-
降低hash冲突办法:
-
计算hash值的时候进行异或运算
-
降低负载因子(load factor),增加数组容量大小
-
计算数组中的位置
-
(n - 1) & hash
-
根据Hash值和数组长度减1进行与运算;相当于对数组长度取模运算,保证取模后结果在数组长度范围内;与运算速度要比取模运算快
- 数组容量大小是2的n次方,可以保证数组大小-1后与hash值与运算后结果在数组范围内,取代模运算,效率更高
HashMap扩容机制
-
扩容时会先判断容量是否有初始化,如果没有则先初始化为默认容量16或者传入的容量,容量最大不能超过2的30次方
-
然后判断当前容量是否超过阈值,默认是当前容量的3/4,如果超过则进行扩容,每次扩容会把容量增加到原来的2倍
-
接着会将原来数组中的数据根据hash值复制到扩容后的数组中,在拷贝数据过程中,原有链表或者红黑树会被拆分成两份,一部分会保存在原有数组位置,另一部分会存在当前数组位置加上原有数组容量大小的位置
-
根据if ((e.hash & oldCap) == 0) 判断链表中的元素是否需要移动,如果等于0则不移动,否则移动到当前数组位置加上旧数组容量大小的位置:newTab[j+oldCap]
- 因为同一个Hash值跟数组扩容前和扩容后的大小进行取模运算后,只有两种情况,要么跟原来位置不变,要么比原来位置多原来数组容量大小
-
扩容导致死循环问题
- 因为在1.7版本中,HashMap扩容时采用的是头插法,也就是拷贝旧数组中元素到新数组中时,新元素是插入到链表头部的,当并发时可能出现多个线程同时在扩容,当其中一个线程正在将元素A移动到新的位置时,A的下一个元素时B,另一个线程正在将B插入A的前面,但是A指向B的链接还没有断开,B就指向了A,这就会导致A和B互相链接着形成环状,当调用get方法遍历链表时就可能会卡死在这里永远无法退出循环
HashMap如何保证线程安全
HashTable
-
底层实现也是数组+链表
-
使用了Synchronized同步锁,会锁住整个HashTable对象,效率低
-
线程安全,key和value都不能为null
ConcurrentHashMap
-
线程安全
-
将整个Map分成N个段Segment保存在数组中,每个Segment又可以看做一个小型的HashMap,内部由数据+链表结构实现,Segment继承自可重入锁;
-
锁分段技术,每一个Segment都是一个可重入锁,每次只会锁住该段中的元素,不会影响到其他段中元素的读写
-
扩容采用段内扩容,每次扩容只针对当前Segment,不会对整个表扩容
-
有些操作需要锁定整个表,比如获取所有元素个数size,或者判断某个元素是否在表中containsValue操作
- 在计算size时会先尝试几次不加锁统计,当发现算了几次结果都一样时,则任务没有新增或者删除,如果有变化则强制将所有Segment加锁后再统计
-
jdk1.8后的变化:
-
参考地址:https://blog.csdn.net/qq_26542493/article/details/105651338&cd=1&hl=zh-CN&ct=clnk&gl=ph&strip=1
HashMap是否有序,如何保证有序?
无序的,LinkedHashMap可以保证有序
为什么容量必须是2的N次方
- 很多地方用到二进制运算,比如计算hash值,计算数组中的位置,扩容等;使用2的N次方转成二进制就是一个1,其他都是0,方便二进制运算
参考链接:https://blog.csdn.net/qq_26542493/article/details/105482732&cd=1&hl=zh-CN&ct=clnk&gl=ph&strip=1
相关文章:
HashMap源码分析小结
HashMap相关问题 HashMap实现原理 HashMap是以键值对的形式存储数据,内部是通过数组链表结构实现,在1.7之后的版本,链表结构可以升级为红黑树,提高查询效率 key和value都支持为null;key为null时hash值是0࿰…...

太奇怪了!小公司面试全挂,大厂面试全过,为什么小公司要求比大厂还高?...
大厂的人才去小公司面试,一定是降维打击吗?还真未必。一位网友很困惑:真的奇怪,小公司面试全挂,大厂面试10个过了9个,感觉小公司要求比大厂还高,这是怎么了?来看看网友们的看法。有人…...
Java开发环境配置
Java开发环境配置 Java是目前世界上最流行的编程语言之一,它的使用范围广泛,从Web应用程序到桌面应用程序再到移动应用程序,Java都是一种非常有用的语言。想要进行Java开发,首先需要在计算机上配置Java开发环境。 在本文中&…...

大学英语视听说教程(陈向京版本)
词汇题(55道) 1. You should carefully think over_____ the manager said at the meeting. A. that B. which C. what D. whose 1.选C,考察宾语从句连接词,主句谓语动词think over后面缺宾语,后面的宾语从句谓语动…...
nginx--开源免费
nginx开源免费,支持高性能,高并发的web服务和代理服务软件。 apache,nodejs nginx可以提供的服务: 1、web服务 2、负载均衡(反向代理)(动静分离) 3、web cache(web缓存) nginx…...

阿里云OSS对象存储
目录 1:OSS 1.1:开通OSS服务 1.2:搭建OSS环境 1.2.1:创建Bucket存储空间 1.2.2:创建文件夹上传图片 1.2.3:RAM访问控制 1.3:快速入门 1.3.1:下载SDK 1.3.2:搭建环…...

基于VHDL语言的汽车测速系统设计_kaic
摘 要 汽车是现代交通工具。车速是一项至关重要的指标。既影响着汽车运输的生产率,又关乎着汽车行驶有没有超速违章,还影响着汽车行驶时人们的人身安全。而伴随着我国国民的安全防范意识的逐步增强,人们也开始越来越关心因为汽车的超速而带来的极其严重…...

【数据结构】单链表(笔记总结)
👦个人主页:Weraphael ✍🏻作者简介:目前学习C和算法 ✈️专栏:数据结构 🐋 希望大家多多支持,咱一起进步!😁 如果文章对你有帮助的话 欢迎 评论💬 点赞&…...
Git操作之 git add 撤销、git commit 撤销
1、git add 添加多余文件 撤销操作 git reset HEAD 后面什么都不跟的,就是上一次add 里面的内容全部撤销 git reset HEAD XXX 后面跟文件名,就是对某个文件进行撤销 2、git commit 撤销操作 git reset --soft HEAD^ 这样就成功的撤销了commit操作 注…...
用PyTorch实现MNIST数据集手写数字识别
资源下载:用Pytorch实现MNIST数据集的手写数字识别介绍资源-CSDN文库 手写数字识别是一项相当普遍的应用,因为在现实生活中,我们经常需要对手写数字进行识别,例如在邮政服务中,我们需要对邮件上的邮政编码进行识别&am…...
leetcode3:无重复字符的最长子串
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: s “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。 示例 2: 输入: s “bbbbb” 输出: 1 解释: 因为无重复字符的最长子串是 “…...

ChatGPT让现在的软件都土掉渣了
我们家有两个娃,每次我们想要出去时订个酒店时都好麻烦。我在某程上找,我先看有没有家庭房,但家庭房很少,而且有些家庭房实际上只能睡得下两大一小。普通房间能不能睡得下四个人,那可是得查看很多信息,如床…...

IU5708D低静态电流同步升压DC-DC 控制器
IU5708D是高性能宽输入范围 (4.5V~40V) 同步升压控制器,支持高达52V的输出电压。输出电压采用恒定频率电流模式脉宽调制(PWM) 控制来实现调节。 芯片通过外部定时电阻器或通过与外部时钟信号同步来设置开关频率。在电阻编程模式下,开关频率可从50KHz编程…...
ubuntu查看软件安装路径
ubuntu怎么查看软件安装位置在哪 - 服务器 - 亿速云 1、执行程序查看 在终端使用type执行软件程序查看。 type google-chrome 2、通过进程查看对应的软件程序 在终端使用以下命令查看所有进程名。 ps -e 再使用以下过滤命令查看对应的进程信息即可。 ps aux|grep 软件名 …...

动态规划总结
1,01背包dp(每件物品最多选一次): 因为背包为0 的时候,什么都装不了,所以为零 ,就是他们的最优解。 最后一个单元格为最后的答案。 01背包模板 public class Knapsack {public static int kn…...

分享:数据库存储与索引技术(一)存储模型与索引结构演变
欢迎访问 OceanBase 官网获取更多信息:https://www.oceanbase.com/ 本文来自OceanBase社区分享,仅限交流探讨。原作者马伟,长期从事互联网广告检索系统的研发,对数据库,编译器等领域也有浓厚兴趣。 文章目录综述传统单…...

ZeusAutoCode代码生成工具(开源)
ZeusAutoCode代码生成工具 一、简介 Zeus代码生成器是一款自动代码生成工具,旨在快速生成基础的CRUD代码,在此基础上也提供了一些高级功能,做到灵活配置,生成可扩展性强的代码。 后端是基于springboot、freemarker、mybatisplu…...

算法题记录
力扣的算法题:1154 给你一个字符串 date ,按 YYYY-MM-DD 格式表示一个 现行公元纪年法 日期。返回该日期是当年的第几天。 示例 1: 输入:date “2019-01-09” 输出:9 解释:给定日期是2019年的第九天。 示例…...

章节2 行走数据江湖,只需一行代码
目录6. 函数填充,计算列6.1 excel操作6.2 pandas操作16.3 pandas操作28. 数据筛选、过滤,[绘图前的必备功课]8.1 excel操作8.2 Python操作http://sa.mentorx.net 蔓藤教育6. 函数填充,计算列 书的编号、书的名字、标价、折扣、最终价钱 最终…...

springboot集成xx-job;
概念理解: xx-job是一个分布式任务调度平台。比如你有AB两个项目。 AB的定时任务就要在xx-job上个注册。同时AB要配置对应的依赖。 所以集成xx-job要分2步骤:第一步:先搭建xx-job服务 第二步,在A项目中导包并引用。 第一步&am…...

IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...

JavaSec-RCE
简介 RCE(Remote Code Execution),可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景:Groovy代码注入 Groovy是一种基于JVM的动态语言,语法简洁,支持闭包、动态类型和Java互操作性,…...

(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...