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…...
以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...
push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...
CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝
目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为:一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...
