赞美对方公司网站做的好的日语/专业软文发布平台
目录
- 一、知识点回顾
- 二、HashMap 的 put() 和 get() 的实现
- 2.1 map.put(k, v) 实现原理
- 2.2 map.get(k) 实现原理
- 三、HashMap 的常见面试题
- 3.1 为何随机增删、查询效率都很高?
- 3.2 为什么放在 HashMap 集合 key 部分的元素需要重写 equals 方法?
- 3.3 HashMap 的 key 为什么是无序的?
- 3.4 HashMap 怎么保持不可重复?
- 3.5 HashMap 是如何扩容的?
- 3.4 HashMap 在 JDK7 和 JDK8 有什么不同?
- 3.5 HashMap 的哈希碰撞
- 3.6 HashMap 的 key 允许为 null 吗?
HashMap的底层是通过
数组
+单向链表/红黑树
实现的。
一、知识点回顾
数组特点:
- 存储区间是连续的,且占用内存严重,空间复杂度也很大,时间复杂度为 O(1)。
- 优点: 随机读取效率很高,原因是数组是连续的(随机访问性强,查找速度快)。
- 缺点: 插入和删除数据效率低,因插入数据,这个位置后面的数据在内存中要后移,且大小固定不易动态扩展。
链表特点:
- 区间离散,占用内存宽松,空间复杂度小,时间复杂度 O(n)。
- 优点: 插入删除速度快,内存利用率高,没有大小固定,扩展灵活。
- 缺点: 不能随机查找,每次都是从第一个开始遍历(查询效率低)。
哈希表特点:
以上数组和链表,大家都知道各自优缺点。那么我们能不能把以上两种结合在一起使用,从而实现查询效率高和删除插入效率也高的数据结构呢?答案是可以滴,那就是哈希表
可以满足,接下来我们一起复习下 HashMap 中的 put() 和 get() 方法实现原理。

二、HashMap 的 put() 和 get() 的实现
2.1 map.put(k, v) 实现原理
-
第1步,首先将 k, v 封装到 Node 对象当中(节点)。
-
第2步,它的底层会调用 K 的 hashCode() 方法得出 hash 值。
-
第3步,通过哈希表函数/哈希算法,将 hash 值转换成数组的下标:
- 下标位置上如果没有任何元素,就把 Node 添加到这个位置上;
- 如果说下标对应的位置上有链表,就会拿着 k 和链表上每个节点的 k 进行 equals:
- 如果所有的 equals 方法返回都是 false,那么这个新的节点将被添加到链表的末尾;
- 如其中有一个 equals 返回了 true,那么这个节点的 value 将会被覆盖。
2.2 map.get(k) 实现原理
- 第1步,先调用 k 的 hashCode() 方法得出哈希值,并通过哈希算法转换成数组的下标。
- 第2步,通过上一步哈希算法转换成数组的下标之后,再通过数组下标快速定位到链表所在位置上。
- 如果这个位置上什么都没有,则返回 null;
- 如果这个位置上有单向链表,那么它就会拿着参数 k 和单向链表上的每一个节点的 k 进行 equals:
- 如果所有 equals 方法都返回 false,则 get 方法返回 null;
- 如果其中一个节点的 k 和参数 k 进行 equals 返回 true,那么此时该节点的 value 就是我们要找的 value 了,get 方法最终返回这个要找的 value。
三、HashMap 的常见面试题
3.1 为何随机增删、查询效率都很高?
增删是在链表上完成的,而查询主要是通过数组定位,然后扫描部分链表,所以效率高。
HashMap 集合的 key,会先后调用两个方法:hashCode() 和 equals() 方法,所以当对象充当 key 时,这两个方法都需要重写。
3.2 为什么放在 HashMap 集合 key 部分的元素需要重写 equals 方法?
因为 equals 默认比较的是两个对象的内存地址,如果想根据对象的属性来判断,则需要重写。
3.3 HashMap 的 key 为什么是无序的?
因为不一定挂到哪一个单向链表上,因此加入顺序和取出也不一样。
3.4 HashMap 怎么保持不可重复?
使用 equals 方法来保证 HashMap 的 key 不可重复。如果 key 重复的话,value 就会覆盖。存放在 HashMap 集合中的 key,其实就是存放在 HashSet 集合中,所以 HashSet 集合也需要重写 equals() 和 hashCode() 方法。
3.5 HashMap 是如何扩容的?
HashMap 集合的默认初始化容量为16,默认加载因子为 0.75,也就是说当 HashMap 集合底层数组的容量达到 75% 时,数组就开始扩容。HashMap 集合初始化容量是 2 的倍数,是为了达到散列均匀,提高 HashMap 集合的存取效率。
3.4 HashMap 在 JDK7 和 JDK8 有什么不同?
-
new HashMap<>()
,底层不会再创建一个长度为 16 的数组,改为首次调用put()
方法时创建; -
jdk8 底层的数组是
Node[]
,而非Entry[]
; -
jdk7 底层结构只有:
数组+链表
,jdk8 中底层结构:数组+链表+红黑树
。3.1 形成链表时,
七上八下
jdk7:头插法,新元素指向旧元素(多线程修改会有死锁问题);
jdk8:尾插法,旧元素指向新元素;
3.2 为什么要用红黑树:
- 首先,正常场景下不会一下子产生特别多的 Hash 冲突,只有非常规的场景下才会出现 Hash 冲突,需要转化为红黑树结构。
- 红黑树解决了超长链表查询效率低下的问题,但是小数据量的链表并不比红黑树的查询效率要低。
- Hash 值如果足够随机,则在 Hash 表内按
泊松分布
,在负载因子 0.75 的情况下,长度超过 8 的链表出现概率时 0.00000006,选择 8 就是为了尽量降低树化的几率。
3.3 树化的两个条件:(必须都满足)
- 哈希单向链表中的元素数 > 8
- 当前数组的长度 > 64
3.4 退化链表的条件:(任何一个满足)
- 红黑树上的节点数 < 6
- remove 节点时,若 root、root.left、root.right、root.left.left 有任意一个为 null,也会退化为链表。
3.5 HashMap 的哈希碰撞
如果 key1 和 key2 的哈希值相同,就会存放到同一个单向链表上。
如果 key1 和 key2 的哈希值不同,但由于哈希算法执行结束之后转换的数组下标可能相同,此时会发生哈希碰撞
。
3.6 HashMap 的 key 允许为 null 吗?
允许
JDK8 中 HashMap 的 put() 方法:
public V put(K key, V value) {// 采用 hash(key) 来计算 key 的 hashCode 值return putVal(hash(key), key, value, false, true);
}static final int hash(Object key) {int h;// 当 key 为 null 的时候,不走 hashCode() 方法return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
HashMap 中使用 hash() 方法来计算 key 的哈希值,当 key 为 null 时,直接令 key 的哈希值为0,不走 key.hashCode() 方法,所以即使为 null 也不会抛出空指针异常。
整理完毕,完结撒花~ 🌻
参考地址:
1.来复习一波,HashMap底层实现原理解析,https://baijiahao.baidu.com/s?id=1665667572592680093&wfr=spider&for=pc
2.java中的hashMap允许key为null的原因,https://blog.csdn.net/weixin_46984636/article/details/120606095
3.HashMap,https://blog.csdn.net/qq_39181839/article/details/109478003
4.HashMap,https://blog.csdn.net/weixin_42470732/article/details/124027786
相关文章:

HashMap底层的实现原理(JDK8)
目录一、知识点回顾二、HashMap 的 put() 和 get() 的实现2.1 map.put(k, v) 实现原理2.2 map.get(k) 实现原理三、HashMap 的常见面试题3.1 为何随机增删、查询效率都很高?3.2 为什么放在 HashMap 集合 key 部分的元素需要重写 equals 方法?3.3 HashMap 的 key 为…...

操作系统-整理
进程 介绍 进程是系统进行资源分配和调度的一个独立单位。每个进程都有自己的独立内存空间,不同进程通过进程间通信来通信。由于进程占据独立的内存,所以上下文进程间的切换开销(栈、寄存器、虚拟内存、文件句柄等)比较大&#…...

系统换行符的思考
各系统换行符 换行符,也即是回车换行,因为表示为Carriage-Return和Line-Feed。 回车用Return-Carrige表示,简写为CR,字符表示为\r。 换行用Line-Feed表示,简写为LF,字符表示为\n。 由于历史原因…...

Wwise集成到unreal
1、Wwise集成到Unreal 1.1 安装必要的软件 安装unreal 5.1;安装Audiokinetic Launcher;集成版本是Wwise 2021.1.12.7973。Audiokinetic Launcher下载地址: https://www.audiokinetic.com/zh/thank-you/launcher/windows/?refdownload&pl…...

前端秘籍之=>八股文经卷=>(原生Js篇)【持续更新中...】
大家好,最近想了想,打算总结归纳一版前端八股文经卷,给大家提供学习参考,如果帮助到大家,请大家,一键三连支持一下,你们的支持会激励我更加努力的更新更多有用的知识,博主先在这里谢…...

【Python安装配置教程】
Python由荷兰数学和计算机科学研究学会的吉多范罗苏姆于1990年代初设计,作为一门叫做ABC语言的替代品。Python提供了高效的高级数据结构,还能简单有效地面向对象编程。Python语法和动态类型,以及解释型语言的本质,使它成为多数平台…...

Spring-Retry失败重试
文章目录 重试的场景引入依赖启动类serviceController@Retryable参数@Recover注意事项重试的场景 1、网络波动需要,导致请求失败,需要重发。 2、发送消息失败,需要重发,重发失败要记录日志 … 引入依赖 <!-- spring-retry--> <dependency><groupId>or…...

【目标检测 DETR】通俗理解 End-to-End Object Detection with Transformers,值得一品。
文章目录DETR1. 亮点工作1.1 E to E1.2 self-attention1.3 引入位置嵌入向量1.4 消除了候选框生成阶段2. Set Prediction2.1 N个对象2.2 Hungarian algorithm3. 实例剖析4. 代码4.1 配置文件4.1.1 数据集的类别数4.1.2 训练集和验证集的路径4.1.3 图片的大小4.1.4 训练时的批量…...

项目ER图和资料
常用的数据类型 模型类 一对多 from app import db import datetimeclass BaseModel(db.Model):__abstract__ Truecreate_time db.Column(db.DateTime,defaultdatetime.datetime.now())update_time db.Column(db.DateTime,defaultdatetime.datetime.now())class Role(db.M…...

剑指 Offer 20. 表示数值的字符串(java+python)
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。 数值(按顺序)可以分成以下几个部分: 若干空格 一个 小数 或者 整数 (可选)一个 ‘e’ 或 ‘E’ ,后面跟着一个 整数…...

程序员的逆向思维
前要: 为什么你读不懂面试官提问的真实意图,导致很难把问题回答到面试官心坎上? 为什么在面试结束时,你只知道问薪资待遇,不知道如何高质量反问? 作为一名程序员,思维和技能是我们职场生涯中最重要的两个方面。有时候…...

吐血整理学习方法,2年多功能测试成功进阶自动化测试,月薪23k+......
目录:导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜)前言 测试进阶方向 测试进…...

mysql慢查询:pt-query-digest 分析
"某些SQL语句执行效率慢",这个问题总体上分为两类: 出现了慢查询语句某些查询语句没有使用索引 由于数据的写入量非常大,所以要想直接打开慢查询日志来查看到底哪些语句有问题几乎是不可能的,因为日志的刷新速度太快了…...

git的使用整合
git的下载和安装暂时不论述了,将git安装后会自动配置环境变量,所以环境变量也不需要配置。 一、初始化配置 打开git bash here(使用linux系统下运行的口令),弹出一个类似于cmd的窗口。 (1)配置属性 git config --glob…...

XCPC第九站———背包问题!
1.01背包问题 我们首先定义一个二维数组f,其中f[i][j]表示在前i个物品中取且总体积不超过j的取法中的最大价值。那么我们如何得到f[i][j]呢?我们运用递推的思想。由于第i个物品只有选和不选两种情况,当不选第i个物品时,f[i][j]f[i…...

【软考 系统架构设计师】论文范文④ 论基于构件的软件开发
>>回到总目录<< 文章目录 论基于构件的软件开发范文摘要正文论基于构件的软件开发 软件系统的复杂性不断增长、软件人员的频繁流动和软件行业的激烈竞争迫使软件企业提高软件质量、积累和固化知识财富,并尽可能地缩短软件产品的开发周期。 集软件复用、分布式对…...

spring-integration-redis中分布式锁RedisLockRegistry的使用
pom依赖:<!-- redis --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.springframework.integ…...

城市通电(prim算法)
acwing3728 蓝桥杯集训每日一题 平面上遍布着 n 座城市,编号 1∼n。 第 i 座城市的位置坐标为 (xi,yi) 不同城市的位置有可能重合。 现在要通过建立发电站和搭建电线的方式给每座城市都通电。 一个城市如果建有发电站,或者通过电线直接或间接的与建…...

【动态规划】
动态规划1引言题目509. 斐波那契数70. 爬楼梯746. 使用最小花费爬楼梯小结53. 最大子数组和结语引言 蓝桥杯快开始了啊,自从报名后还没认真学过算法有(>﹏<)′,临时抱一下佛脚,一起学学算法。 题目 509. 斐波那契数 斐波那契数 &am…...

秒懂算法 | DP概述和常见DP面试题
动态(DP)是一种算法技术,它将大问题分解为更简单的子问题,对整体问题的最优解决方案取决于子问题的最优解决方案。本篇内容介绍了DP的概念和基本操作;DP的设计、方程推导、记忆化编码、递推编码、滚动数组以及常见的DP面试题。 01、DP概述 1. DP问题的特征 下面以斐波那…...

【C++提高编程】C++全栈体系(二十五)
C提高编程 第四章 STL- 函数对象 一、函数对象 1. 函数对象概念 概念: 重载函数调用操作符的类,其对象常称为函数对象函数对象使用重载的()时,行为类似函数调用,也叫仿函数 本质: 函数对象(仿函数)是一个类&…...

【云原生】k8s核心技术—集群安全机制 Ingress Helm 持久化存储-20230222
文章目录一、k8s集群安全机制1. 概述2. RBAC——基于角色的访问控制二、Ingress三、Helm1. 引入2. 使用功能Helm可以解决哪些问题3. 介绍4. 3个重要概念5. helm 版本变化6. helm安装及配置仓库7. 使用helm快速部署应用8. 自己创建chart9. 实现yaml高效复用四、持久化存储1.nfs—…...

【Linux】实现简易的Shell命令行解释器
大家好我是沐曦希💕 文章目录一、前言二、准备工作1.输出提示符2.输入和获取命令3.shell运行原理4.内建命令5.替换三、整体代码一、前言 前面学到了进程创建,进程终止,进程等待,进程替换,那么通过这些来制作一个简易的…...

再获认可!腾讯安全NDR获Forrester权威推荐
近日,国际权威研究机构Forrester发布最新研究报告《The Network Analysis And Visibility Landscape, Q1 2023》(以下简称“NAV报告”),从网络分析和可视化(NAV)厂商规模、产品功能、市场占有率及重点案例等…...

代码审计之旅之百家CMS
前言 之前审计的CMS大多是利用工具,即Seay昆仑镜联动扫描出漏洞点,而后进行审计。感觉自己的能力仍与零无异,因此本次审计CMS绝大多数使用手动探测,即通过搜索危险函数的方式进行漏洞寻找,以此来提升审计能力…...

ONLYOFFICE中利用chatGPT帮助我们策划一场生日派对
近日,人工智能chatGPT聊天机器人爆火,在去年年底发布后,仅仅两个月就吸引了全球近一亿的用户,成为史上最快的应用消费程序,chatGPT拥有强大的学习和交互能力 可以被学生,教师,上班族各种职业运…...

Java面试题-线程(一)
在典型的 Java 面试中, 面试官会从线程的基本概念问起, 如:为什么你需要使用线程,如何创建线程,用什么方式创建线程比较好(比如:继承 thread 类还是调用 Runnable 接口),…...

一篇普通的bug日志——bug的尽头是next吗?
文章目录[bug 1] TypeError: method object is not subscriptable[bug 2] TypeError: unsupported format string passed to numpy.ndarray.__format__[bug 3] ValueError:Hint: Expected dtype() paddle::experimental::CppTypeToDataType<T>::Type()[bug 4] CondaSSLE…...

Vue 3 第八章:Watch侦听器
文章目录Watch侦听器1. 基础概念1.1. Watch的基本用法例子1:监听单个ref的值,直接监听例子2:监听多个ref的值,采用数组形式例子3:深度监听例子4:监听reactive响应式对象单一属性,采用回调函数的…...

GlassFish的安装与使用
一、产品下载与安装glassfish下载地址:https://download.oracle.com/glassfish/5.0.1/release/index.html下载后解压即完成安装,主要目录说明:bin目录:为asadmin命令所在目录。glassfish为主目录:glassfish\bin目录为命…...