HashMap底层实现原理解析

article/2025/11/9 13:12:03

一、HashMap底层实现原理解析

我们常见的有数据结构有三种结构:

  • 数组结构
  • 链表结构
  • 哈希表结构

下面我们来看看各自的数据结构的特点:
1)数组结构: 存储区间连续、内存占用严重、空间复杂度大

优点:随机读取和修改效率高,原因是数组是连续的(随机访问性强,查找速度快)
缺点:插入和删除数据效率低,因插入数据,这个位置后面的数据在内存中都要往后移动,且大小固定不易动态扩展。
2)链表结构:存储区间离散、占用内存宽松、空间复杂度小

优点:插入删除速度快,内存利用率高,没有固定大小,扩展灵活
缺点:不能随机查找,每次都是从第一个开始遍历(查询效率低)
3)哈希表结构:结合数组结构和链表结构的优点,从而实现了查询和修改效率高,插入和删除效率也高的一种数据结构

HashMap底层是哈希表结构

在这里插入图片描述HashMap中的put()和get()的实现原理:
1)map.put(k,v)实现原理
(1)首先将k,v封装到Node对象当中(节点)。
(2)然后它的底层会调用K的hashCode()方法得出hash值。
(3)通过哈希表函数/哈希算法,将hash值转换成数组的下标,下标位置上如果没有任何元素,就把Node添加到这个位置上。如果说下标对应的位置上有链表。此时,就会拿着k和链表上每个节点的k进行equal。如果所有的equals方法返回都是false,那么这个新的节点将被添加到链表的末尾。如其中有一个equals返回了true,那么这个节点的value将会被覆盖。
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集合的key,会先后调用两个方法,hashCode and equals方法,这这两个方法都需要重写。

为什么放在hashMap集合key部分的元素需要重写equals方法?
因为equals方法默认比较的是两个对象的内存地址

二、HashMap红黑树原理分析

相比 jdk1.7 的 HashMap 而言,jdk1.8最重要的就是引入了红黑树的设计,红黑树除了插入操作慢其他操作都比链表快,当hash表的单一链表长度超过 8 个的时候,数组长度大于64,链表结构就会转为红黑树结构。当红黑树上的节点数量小于6个,会重新把红黑树变成单向链表数据结构。
为什么要这样设计呢?好处就是避免在最极端的情况下链表变得很长很长,在查询的时候,效率会非常慢。
在这里插入图片描述

  • 红黑树查询:其访问性能近似于折半查找,时间复杂度 O(logn);
  • 链表查询:这种情况下,需要遍历全部元素才行,时间复杂度 O(n);

简单的说,红黑树是一种近似平衡的二叉查找树,其主要的优点就是“平衡“,即左右子树高度几乎一致,以此来防止树退化为链表,通过这种方式来保障查找的时间复杂度为 log(n)。

在这里插入图片描述
关于红黑树的内容,网上给出的内容非常多,主要有以下几个特性:
1、每个节点要么是红色,要么是黑色,但根节点永远是黑色的;

2、每个红色节点的两个子节点一定都是黑色;

3、红色节点不能连续(也即是,红色节点的孩子和父亲都不能是红色);

4、从任一节点到其子树中每个叶子节点的路径都包含相同数量的黑色节点;

5、所有的叶节点都是是黑色的(注意这里说叶子节点其实是上图中的 NIL 节点);
在树的结构发生改变时(插入或者删除操作),往往会破坏上述条件 3 或条件 4,需要通过调整使得查找树重新满足红黑树的条件。

三、HashMap的原理1.7 和1.8 的区别

  1. jdk1.7中底层是由数组+链表实现;jdk1.8中底层是由数组+链表/红黑树实现
  2. 可以存储null键和null值,线程不安全
  3. 初始size为16,扩容:newsize = oldsize*2,size一定为2的n次幂
  4. 扩容针对整个Map,每次扩容时,原来数组中的元素依次重新计算存放位置,并重新插入
  5. 当Map中元素总数超过Entry数组的75%,触发扩容操作,为了减少链表长度,元素分配更均匀

hash冲突
当两个key通过hashCod计算相同时(其实hashCode是随机产生的,是有可能hashCode相同),则发生了hash冲突,开放定址法、再哈希法、链地址法、建立公共溢出区
HashMap解决hash冲突的方式是用链表。当发生hash冲突时,则将存放在数组中的Entry设置为新值的next,说白就是比如A和B都hash后都映射到下标i中,之前已经有A了,当map.put(B)时,将B放到下标i中,A则为B的next,所以新值存放在数组中,旧值在新值的链表上

  • 开放定址法:当关键字key的哈希地址p=H(key)出现冲突时,以p为基础,产生另一个哈希地址p1,如果p1仍然冲突,再以p为基础,产生另一个哈希地址p2,…,直到找出一个不冲突的哈希地址pi ,将相应元素存入其中
  • 再哈希法:同时构造多个不同的哈希函数,当哈希地址Hi=RH1(key)发生冲突时,再计算Hi=RH2(key)……,直到冲突不再产生。
  • 链地址法:这种方法的基本思想是将所有哈希地址为i的元素构成一个称为同义词链的单链表,并将单链表的头指针存在哈希表的第i个单元中,因而查找、插入和删除主要在同义词链中进行。链地址法适用于经常进行插入和删除的情况。
  • 建立公共溢出区:将哈希表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表。

http://chatgpt.dhexx.cn/article/cmbrkmep.shtml

相关文章

HashMap底层实现原理概述

1. 前言 在一场面试中最能打动面试官的其实是细节,候选人对细节的了解程度决定了留给面试官的印象到底是“基础扎实”还是“基础薄弱”,如果候选人能够举一反三主动阐述自己对一些技术细节的理解和总结,那无疑是面试过程中的一大亮点。HashM…

HashMap实现原理分析

之前转载过一篇HashMap相关分析文章,快速链接:HashMap实现原理分析 既然有前辈已经将源码分析总结了出来,我们在继续学习研究源码实现的时候不妨借鉴借鉴前人的总结与经验~ 本文转自:https://blog.csdn.net/hefenglian/article/…

HashMap面试,看这一篇就够了

历史热门文章: 七种方式教你在SpringBoot初始化时搞点事情 Java序列化的这三个坑千万要小心可以和面试官聊半个小时的volatile原理Java中七个潜在的内存泄露风险,你知道几个?JDK 16新特性一览啥?用了并行流还更慢了InnoDB自增原理…

java中HashMap原理

1、为什么用HashMap? HashMap是一个散列桶(数组和链表),它存储的内容是键值对(key-value)映射HashMap采用了数组和链表的数据结构,能在查询和修改方便继承了数组的线性查找和链表的寻址修改HashMap是非synchronized&a…

HashMap的实现原理

1. HashMap概述 HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。 在java编程语言中,最基本的结构就是两种,一个…

软件测试用例分析和用例设计

测试用例的概念 测试用例(test case),也叫测试案例,是为了达到一个最佳的测试效果或者高效的发现软件中的隐藏错误(缺陷)而精心设计的包括场景步骤和数据。 通用的定义:是关于一个功能验证时候…

软件测试用例设计练习

1、完成163邮箱注册用例的编写 邮箱地址:6~18个字符,可使用字母、数字、下划线,需要以字母开头 密码:8~16个字符,大、小写字母、数字、标点符号,3种或以上组合 2、需求:输入三条边&#xff…

软件测试用例详细规范

软件测试用例详细规范 为什么编写测试用例详细测试用例模板测试用例字段介绍用例操作步骤用例预期结果: 测试用例录入原则:测试用例设计步骤测试用例案例:测试用例校验点: 为什么编写测试用例 我也不知道,自己百度 详…

软件测试——测试用例设计方法

1、测试用例定义 测试用例又叫test case,是为某个特殊目标而编制的一组测试输入,执行条件以及预期结果,以便测试某个程序路径或核实是否满足某个特定需求。 2、测试用例的特性 有效性:测试用例能够被使用,且被不同人…

接口测试用例怎么写?

测试流程 需求规格说明书--测试计划--测试用例--用例评审--开发 接口文档--接口分析--接口用例设计--评审--接口测试执行(关注数据库)--前后端对接 系统界面测试--测试结束 如何设计接口测试用例? 1.接口正常调用,先要能跑通…

软件测试 - 用例篇

回顾上一篇博客主要内容:软件测试 - 基础篇 1: 软件测试的流程是什么? 需求分析,测试计划,测试设计/测试开发,测试执行,测试报告 需求分析 分析需求,验证需求的正确性和合理性,从需求中提取出测试项 测试计划 要考虑测试人数,测试环境,测试时间,测试设备等 测试设计/测试开发 …

软件测试用例优先级,软件测试用例的优先级划分方法

随着互联网的不断发展,程序员对于软件品质以及运行状况等参数关注程度也在提高,而今天我们就一起来了解一下,在划分测试用例优先级的时候都有哪些划分方法可以使用。 没有软件系统是完美的,任何系统都有BUGS。但是每一次得迭代都有…

软件测试:测试用例

一、通用测试用例八要素  1、用例编号;  2、测试项目;  3、测试标题;  4、重要级别;  5、预置条件;  6、测试输入;  7、操作步骤;  8、预期输出 二、具体分析通用测试用例八要…

【软件测试】测试用例的设计方法

文章目录 1. 测试用例的概念2. 设计测试用例的好处3. 基于需求设计测试用例3.1 功能性需求3.2 非功能性需求 4. 设计测试用例的具体方法4.1 等价类4.2 边界值4.3 错误猜测法4.4 场景设计法4.5 因果图法4.6 正交法 5. 测试用例的粒度 1. 测试用例的概念 测试用例就是测试人员向…

如何写好测试用例

目录 前言 为什么要写用例? 那怎么写好测试用例呢? 那么我们日常测试中,如果用xmind梳理用例结构注意哪些点呢? 结语 前言 经历过校招或社招的测试同学,都会被问到测试用例的设计、使用方法,以及用例的…

软件测试——测试用例设计测试分类详解

文章目录 1. 测试用例的基本要素2. 测试用例的设计方法2.1 基于需求设计测试用例2.11 功能性需求测试分析2.12 非功能性需求测试分析 2.2 具体的设计测试用例的方法等价类(非常重要)边界值错误猜测法场景法因果图法正交法 3. 测试分类3.1 按照测试对象划…

软件测试-如何写好测试用例

软件测试-如何写好测试用例 一、课程介绍前置知识点 二、测试用例与编写流程介绍测试用例介绍需求分析与测试点编写测试用例编写注意 三、 测试用例编写,评审与管理测试用例编写方法3-2 慕课网注册功能测试用例编写 (13:25)3-3 慕课网搜索,APP下载功能测…

测试用例应该怎么写

一、背景 有些测试同学,写测试用例的时候,直接就是将需求文档上的内容抄一遍,转换成测试用例的格式。没有加入任何自己的思考和理解,没有融入任何测试方法论。测试完全依赖于需求文档的质量,依赖于产品经理保姆级的服…

【软件测试】测试用例设计

目录 🌷1. 测试用例的基本要素 🌷2. 测试用例的设计方法 🌳2.1 基于需求进行测试用例的设计 ⭐️(1)功能需求测试分析 ⭐️(2)非功能需求测试分析 🌳2.2 具体的设计方法 &#…

软件测试用例设计规范

文章目录 1 目的2 规范内容2.1 设计原则2.1.1 可执行性2.1.2 可维护性2.1.3 可代表性2.1.4 可判定性 2.2 必要元素2.2.1 用例包和用例对象名命2.2.2 测试目的2.2.3 测试优先级2.2.4 测试环境2.2.5 前提条件2.2.6 后置关联2.2.7 用例状态 2.3 综合策略2.3.1 必要的边界值分析2.3…