HashMap原理分析

news/2025/2/22 5:31:16/

HashMap原理分析

  • JDK7 HashMap
    • 1、模型介绍
    • 2、底层实现原理
    • 3、描述一下put的过程
    • 4、HashMap扩容机制:
    • 5、HashMap中的循环链表是如何产生的
    • 6、HashMap和HashTable的区别
    • 7、HashMap为什么用红黑树而不用B树?
  • JDK8 HashMap

JDK7 HashMap

1、模型介绍

HashMap在JDK7中采用的基本存储结构都是 数组+链表 形式。它的底层维护一个Entry数组。它会根据计算的hashCode将对应的KV键值对存储到该数组中,一旦发生hashCode冲突,那么就会将该KV键值对放到对应的已有元素的后面, 此时便形成了一个链表式的存储结构。
在这里插入图片描述

2、底层实现原理

它基于hash算法,通过put方法和get方法存储和获取对象。

存储对象时,我们将K/V传给put方法时,它调用K的hashCode计算hash从而得到bucket位置。

获取对象时,我们将K传给get,它调用hashCode计算hash从而得到bucket位置,并进一步调用equals()方法确定键值对。

如果发生碰撞的时候,HashMap通过链表将产生碰撞冲突的元素组织起来。在JDK 8中,如果一个bucket中碰撞冲突的元素超过某个限制(默认是8),则使用红黑树来替换链表,从而提高速度。

3、描述一下put的过程

1、首次扩容:
先判断数组是否为空,若数组为空则进行第一次扩容(resize)16;

2、计算索引:
通过hash算法,计算键值对在数组中的索引;

3、插入数据:
如果当前位置元素为空,则直接插入数据;
如果当前位置元素非空,且key已存在,则直接覆盖其value;
如果当前位置元素非空,且key不存在,则将数据链到链表末端;
若链表长度达到8,则将链表转换成红黑树,并将数据插入树中;

4、再次扩容
如果数组中元素个数(size)超过threshold(capacity * load factor),则再次进行扩容操作。

4、HashMap扩容机制:

1、数组的初始容量为16,而容量是以2的次方扩充的,一是为了提高性能使用足够大的数组,二是为了能使用位运算代替取模运算(据说提升了5~8倍)。

2、数组是否需要扩充是通过负载因子判断的,如果当前元素个数为数组容量的0.75时,就会扩充数组。这个0.75就是默认的负载因子,可由构造器传入。我们也可以设置大于1的负载因子,这样数组就不会扩充,牺牲性能,节省内存。

3、为了解决碰撞,数组中的元素是单向链表类型。当链表长度到达一个阈值时(8),且table数组的大小也到达一个阈值时(64),会将链表转换成红黑树以提高性能。而当链表长度缩小到另一个阈值时(6),又会将红黑树转换回单向链表提高性能。

5、HashMap中的循环链表是如何产生的

循环链表的问题只在JDK7之前才会出现,JDK8以后这个问题被彻底解决。

在多线程的情况下,当重新调整HashMap大小的时候,就会存在条件竞争,因为如果两个线程都发现HashMap需要重新调整大小了,它们会同时试着调整大小。在调整大小的过程中,存储在链表中的元素的次序会反过来,因为在JDK 7中HashMap在进行数据插入时采用的是头插法。如果条件竞争发生了,那么就会产生死循环。

6、HashMap和HashTable的区别

1、HashTable是一个线程安全的Map实现,但HashMap是线程不安全的实现(HashMap在并发执行put操作时,可能会导致形成循环链表,从而引起死循环),所以HashMap比HashTable的性能高一点。
2、HashTable不允许使用null作为key和value,但HashMap可以使用null作为key或value。

7、HashMap为什么用红黑树而不用B树?

B/B+树多用于外存上时,B/B+也被成为一个磁盘友好的数据结构。

HashMap本来是 数组+链表 的形式,链表由于其查找慢的特点,所以需要被查找效率更高的红黑树结构来替换。如果用B/B+树的话,在数据量不是很多的情况下,数据都会“挤在”一个结点里面,这个时候遍历效率就退化成了链表。

JDK8 HashMap

JDK7中HashMap的实现方案有一个明显的缺点,即当Hash冲突严重时,在桶上形成的链表会变得越来越长,这样在查询时的效率就会越来越低,其时间复杂度为O(N)。

JDK8 对 HashMap 进行了一些修改,最大的不同就是利用了红黑树,所以其由 数组+链表+红黑树 组成。它的底层维护一个Node数组。当链表的存储的数据个数大于等于8的时候,不再采用链表存储,而采用了红黑树存储结构。这么做主要是在查询的时间复杂度上进行优化,链表为O(N),而红黑树一直是O(logN),可以大大的提高查找性能。
在这里插入图片描述


http://www.ppmy.cn/news/20891.html

相关文章

单片机开发---ESP32S3移植lvgl+触摸屏

书接上文 《单片机开发—ESP32-S3模块上手》 本章内容 熟悉一下ESP32S3的开发,修改范例程序的lvgl,使之能够匹配现在的显示屏。 具体工作大概为通过SPI接口连接一块SPI串口屏幕,并且适配lvgl,最后加上触摸屏作为输入。 屏幕 …

第九层(7):STL之list

文章目录前情回顾list概念优缺点构造函数赋值函数交换函数容器和大小操作插入操作删除操作单个数据访问反转操作排序下一座石碑🎉welcome🎉 ✒️博主介绍:一名大一的智能制造专业学生,在学习C/C的路上会越走越远,后面不…

大数据专业前景怎么样?

大数据专业毕业生未来的岗位选择空间比较大,有三大类岗位可选择分别是大数据开发岗位、大数据分析岗位和大数据运维岗位,在不同的行业和技术体系结构下这些岗位也包含很多细分的岗位。 大数据开发岗位分为平台研发岗位和行业场景开发岗位两大类&#xf…

Leetcode力扣秋招刷题路-0114

从0开始的秋招刷题路,记录下所刷每道题的题解,帮助自己回顾总结 114. 二叉树展开为链表(Mid) 给你二叉树的根结点 root ,请你将它展开为一个单链表: 展开后的单链表应该同样使用 TreeNode ,其中…

测牛学堂:软件测试开发python入门之list列表详解(一)

1列表详解 列表,在python中是list,使用[] 注意: 1 列表可以存放任意多的数据 2 列表中可以存放任意类型的数据 3 列表中数据之间,使用逗号分隔 列表的定义方式 1 使用list进行定义。list定义列表,也称为数据类型转换。…

MyBatisPlus入门

文章目录MyBatisPlus1,MyBatisPlus入门案例与简介1.1 入门案例步骤1:创建数据库及表步骤2:创建SpringBoot工程步骤3:勾选配置使用技术步骤4:pom.xml补全依赖步骤5:添加MP的相关配置信息步骤6:根据数据库表创建实体类步骤7:创建Dao接口步骤8:编写引导类步骤9:编写测试…

Linux常用的一些实战脚本(持续更新)

目录 一:根据PID过滤进程所有信息 二:根据进程名过滤进程信息 三:根据用户名查询该用户的相关信息 四:加固系统的一些配置 五:实现磁盘分区的 六:使用一整块硬盘创建逻辑卷 七:将一块硬盘…

【授权与认证】OAuth 2.0 和 OIDC 的异同点

开发者谈 | OAuth 2.0 和 OIDC 协议的关系?(内含必看案例) 【Web 安全】CSRF 攻击详解 OAuth 2.0 OAuth 2.0 的一个简单解释OAuth 2.0 的四种方式什么是Oauth2.0,Oauth2.0的四种授权模式 简单说,OAuth 就是一种授权…