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

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 为什么是无序的?
      • 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 有什么不同?

  1. new HashMap<>(),底层不会再创建一个长度为 16 的数组,改为首次调用 put() 方法时创建;

  2. jdk8 底层的数组是 Node[],而非 Entry[]

  3. 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 为何随机增删、查询效率都很高&#xff1f;3.2 为什么放在 HashMap 集合 key 部分的元素需要重写 equals 方法?3.3 HashMap 的 key 为…...

操作系统-整理

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

系统换行符的思考

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

Wwise集成到unreal

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

前端秘籍之=>八股文经卷=>(原生Js篇)【持续更新中...】

大家好&#xff0c;最近想了想&#xff0c;打算总结归纳一版前端八股文经卷&#xff0c;给大家提供学习参考&#xff0c;如果帮助到大家&#xff0c;请大家&#xff0c;一键三连支持一下&#xff0c;你们的支持会激励我更加努力的更新更多有用的知识&#xff0c;博主先在这里谢…...

【Python安装配置教程】

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

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)

请实现一个函数用来判断字符串是否表示数值&#xff08;包括整数和小数&#xff09;。 数值&#xff08;按顺序&#xff09;可以分成以下几个部分&#xff1a; 若干空格 一个 小数 或者 整数 &#xff08;可选&#xff09;一个 ‘e’ 或 ‘E’ &#xff0c;后面跟着一个 整数…...

程序员的逆向思维

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

吐血整理学习方法,2年多功能测试成功进阶自动化测试,月薪23k+......

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 测试进阶方向 测试进…...

mysql慢查询:pt-query-digest 分析

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

git的使用整合

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

XCPC第九站———背包问题!

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

【软考 系统架构设计师】论文范文④ 论基于构件的软件开发

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

spring-integration-redis中分布式锁RedisLockRegistry的使用

pom依赖&#xff1a;<!-- redis --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.springframework.integ…...

城市通电(prim算法)

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

【动态规划】

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

秒懂算法 | DP概述和常见DP面试题

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

智慧医疗能源事业线深度画像分析(上)

引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

【JavaEE】-- HTTP

1. HTTP是什么&#xff1f; HTTP&#xff08;全称为"超文本传输协议"&#xff09;是一种应用非常广泛的应用层协议&#xff0c;HTTP是基于TCP协议的一种应用层协议。 应用层协议&#xff1a;是计算机网络协议栈中最高层的协议&#xff0c;它定义了运行在不同主机上…...

GitHub 趋势日报 (2025年06月08日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

技术栈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 主题模式…...

LabVIEW双光子成像系统技术

双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制&#xff0c;展现出显著的技术优势&#xff1a; 深层组织穿透能力&#xff1a;适用于活体组织深度成像 高分辨率观测性能&#xff1a;满足微观结构的精细研究需求 低光毒性特点&#xff1a;减少对样本的损伤…...

Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐&#xff1a;「storms…...

PH热榜 | 2025-06-08

1. Thiings 标语&#xff1a;一套超过1900个免费AI生成的3D图标集合 介绍&#xff1a;Thiings是一个不断扩展的免费AI生成3D图标库&#xff0c;目前已有超过1900个图标。你可以按照主题浏览&#xff0c;生成自己的图标&#xff0c;或者下载整个图标集。所有图标都可以在个人或…...

PydanticAI快速入门示例

参考链接&#xff1a;https://ai.pydantic.dev/#why-use-pydanticai 示例代码 from pydantic_ai import Agent from pydantic_ai.models.openai import OpenAIModel from pydantic_ai.providers.openai import OpenAIProvider# 配置使用阿里云通义千问模型 model OpenAIMode…...

基于stm32F10x 系列微控制器的智能电子琴(附完整项目源码、详细接线及讲解视频)

注&#xff1a;文章末尾网盘链接中自取成品使用演示视频、项目源码、项目文档 所用硬件&#xff1a;STM32F103C8T6、无源蜂鸣器、44矩阵键盘、flash存储模块、OLED显示屏、RGB三色灯、面包板、杜邦线、usb转ttl串口 stm32f103c8t6 面包板 …...

Axure零基础跟我学:展开与收回

亲爱的小伙伴,如有帮助请订阅专栏!跟着老师每课一练,系统学习Axure交互设计课程! Axure产品经理精品视频课https://edu.csdn.net/course/detail/40420 课程主题:Axure菜单展开与收回 课程视频:...