深入解析Java 8中HashMap的底层原理

引言

HashMap是Java中常用的集合类,用于存储键值对。其底层实现经过多次优化,包括哈希算法、数组扩容、链表转红黑树等。本文将深入研究HashMap的底层原理,并详细探讨如何解决哈希碰撞的技术。

1. 哈希算法

HashMap的核心是哈希算法,它通过将键的哈希码映射到数组索引,实现快速的数据查找和插入。在JDK 1.8中,哈希算法经过了一些优化,以提高均匀性和减少碰撞的可能性。

2. 数组与链表结构

HashMap的底层数据结构是一个数组,每个数组元素是一个链表(或红黑树)。当多个键映射到相同的索引位置时,它们将被存储在同一个链表中。为了解决哈希碰撞,链表中存储的是一个个键值对。

3. 键值对的存储

HashMap中,键值对以Node对象的形式存储。每个Node包含键、值、哈希码以及指向下一个Node的引用。当产生哈希冲突时,新的Node将被添加到链表的末尾。

4. 解决哈希碰撞的方法

  1. 链地址法:当发生哈希冲突时,将冲突的元素以链表的形式链接在一起,同一个链表上的元素哈希值相同。
    在这里插入图片描述

  2. 红黑树:当链表长度超过一定阈值(默认为8)时,链表会转换为红黑树,可以减少查找时间。因为红黑树的时间复杂度为O(logn),而链表为O(n)。

  3. 扩容rehash:当HashMap中的元素数量太多,超过数组大小*加载因子时,会发生扩容。扩容后,需要对原数组中的所有元素重新计算哈希值,然后放到新的扩容后的数组中,这样可以增加链表长度,减少哈希冲突。

  4. 优化哈希算法:JDK 1.8中优化了哈希算法,通过hashCode()的高16位异或低16位实现的:(h = k.hashCode()) ^ (h >>> 16),提高了哈希碰撞分布性。

所以Java 8中HashMap主要通过链地址法+红黑树+扩容rehash+优化哈希算法来解决哈希冲突。这些方法相结合可以有效地解决哈希冲突问题,提高HashMap的性能。

5. 数组扩容机制

HashMap中的元素数量超过容量乘以加载因子时,数组会被扩容。在JDK 1.8中,默认加载因子是0.75。扩容涉及到重新计算哈希码、重新分配数组,并将现有元素重新放置到新的数组中。这确保了HashMap的性能和空间的平衡。

6. 红黑树的引入

为了应对链表过长的情况,JDK 1.8引入了红黑树。当链表长度达到8时,链表将被转换为红黑树,以提高查找效率。红黑树的引入使得在最坏情况下,查找时间复杂度从O(n)降低到O(log n)。

为什么当链表长度达到8时,链表将被转换为红黑树,又为什么红黑树转链表的阈值为6?
首先和hashcode碰撞次数的泊松分布有关,主要是为了实现时间和空间的平衡,在负载因子为0.75默认情况下,单个hash槽内元素个数为8的概率小于百万分之一,将7作为一个分水岭,等于7时不做转换,大于等于8才转红黑树,小于等于6才转链表,链表中元素个数为8时的概率已经非常小,再多的就更少了,所以原作者在选择链表元素个数时选择了8,是根据概率统计而选择的,红黑树中的TreeNode,是链表中的Node所占空间的2倍,虽然红黑树的查找效率为o(logN),要优于链表的o(N),但是当链表长度比较小的时候,即使全部遍历,时间复杂度也不会太高,所以,要寻找一种时间和空间的平衡,即在链表长度达到一个阈值,之后再转换为红黑树,之所以是8,是因为Java的源码贡献者,在进行大量实验发现,hash碰撞发生8次的概率,已经降低到了0.00000006,几乎为不可能事件,如果真的碰撞发生了8次,那么这个时候说明由于元素,本身和hash函数的原因,此次操作的hash碰撞的可能性非常大了,后序可能还会继续发生hash碰撞,所以,这个时候,就应该将链表转换为红黑树了,也就是为什么链表转红黑树的阈值是8;
最后,红黑树转链表的阈值为6,主要是因为:如果也将该阈值设置于8,那么当hash碰撞在8时,会反生链表和红黑树的不停相互激荡转换,白白浪费资源。

7. 在Java 8中的实现细节

在JDK 1.8中,HashMap的实现经过了优化,包括更好的哈希算法、红黑树的引入、链表长度的控制等。这些变化使得HashMap在面对各种情况时都能提供高效的性能。

8. 性能优化与注意事项

在使用HashMap时,需要注意一些性能优化的问题,例如合理选择初始容量和加载因子、避免频繁扩容等。对于特定的应用场景,可以通过调整这些参数来达到更好的性能。

结论

HashMap作为Java中常用的数据结构之一,在JDK 1.8中经过了一系列的优化和改进。深入理解其底层原理,包括哈希算法、数组与链表结构、红黑树的引入等,以及如何解决哈希碰撞的技术,有助于更好地使用和理解HashMap的性能特性。在实际应用中,根据具体场景选择适当的参数,可以更好地发挥HashMap的优势,提高程序的性能和效率。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/163082.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【运动规划】191 自适应跟踪kinodynamicrrt的路径

分层法: two layer approach 自适应控制,跟随轨迹。运动规划:扩展自由空间(基于速度约束缩小自由空间)为控制部分留余量,确保安全。 控制设计: 考虑平移和旋转,速度环控制&#xff…

银河麒麟安装Docker

# 配置阿里云 Centos8 镜像源,需要额外的一些依赖,而这些依赖在麒麟官方的源里面是没有的 sudo curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-8.repo# 配置阿里云 docker 镜像源 sudo yum-config-manager --add-r…

【23真题】Top3!最高148分,数二英二!

今天分享的是23年西安交通大学815的信号与系统数字信号处理试题及解析。众所周知,Top3一共有10所,其中就包括了西安交大! 本套试卷难度分析:平均分为117-128分,最高分为148分!22年西安交大909/815的真题我…

2022-4-11 南科大现代控制与最优估计

CLEAR_LAB B站视频 矩阵的分块矩阵操作 diagonal 对角阵 identity matrix 单位矩阵 矩阵克罗内克积

【LeetCode二叉树进阶题目】606. 根据二叉树创建字符串,102. 二叉树的层序遍历,107. 二叉树的层序遍历 II

二叉树进阶题目 606. 根据二叉树创建字符串解题思路及实现 102. 二叉树的层序遍历解题思路及实现 107. 二叉树的层序遍历 II解题思路及实现 606. 根据二叉树创建字符串 描述 给你二叉树的根节点 root ,请你采用前序遍历的方式,将二叉树转化为一个由括号…

Python dbm库:利用键值对存储数据

更多Python学习内容:ipengtao.com 大家好,我是涛哥,今天为大家分享 Python dbm库:利用键值对存储数据,文章6000字,阅读大约20分钟,大家enjoy~~ Python中的dbm模块提供了一种轻量级的数据库管理工…

redis---主从复制及哨兵模式(高可用)

主从复制 主从复制:主从复制是redis实现高可用的基础,哨兵模式和集群都是在主从复制的基础之上实现高可用。 主从负责的工作原理 1、主节点(master) 从节点(slave)组成,数据复制是单向的&a…

VUE+element可以为空不为空时只能为(正整数和0)的验证

rule{ 变量: [ { required: true, validator: validateparamPosition, trigger: blur }] } ​​​​​​​ ​​​​​​​ ​​​​​​​ var validateparamPosition (rule, value, callback) > { if (!value) { //先判断空可以过 ca…

【HarmonyOS】JSON格式化解析Map数据失败

【关键字】 数据转换、JSON.stringify、Object.fromEntries 【问题背景】 将数组转换成Map对象,然后调用let str JSON.stringify(newMap),将Map转换成字符串,转换出来的结果是{} 问题代码: let data [{ key: where, value: …

python数据结构与算法-13_高级排序算法-快速排序

快速排序 快速排序名字可不是盖的,很多程序语言标准库实现的内置排序都有它的身影,我们就直奔主题吧。 和归并排序一样,快排也是一种分而治之(divide and conquer)的策略。归并排序把数组递归成只有单个元素的数组,之后再不断两两…

docker安装mysql挂着目录和mysql备份和恢复

第一,镜像拉取,运行镜像并挂载目录,尝试挂bin下,启动不了,不知为啥 docker run --privilegedtrue -itd --namevmysql -p 3306:3306 -v /home/vmysql:/home/vmysql -e MYSQL_ROOT_PASSWORD123456 mysql(图…

Nancy (二)

最近做CS项目,一直在使用TCPSocket 做数据传输,不太爽,砸门可是多年BS的开发,这样开发接口出去比较费劲,但是又不想用asp.net mvc webapi,要按照IIS,有些工控机的系统环境也是很尴尬的,那么也可…

用好说 AI 玩转奥特曼表情包,居然还能和他们聊个天

你喜欢奥特曼吗?你相信光吗? 如果你已经追完了特摄剧、刷完了大电影、用滥了那几个表情包,那不如来试试用 AI 给自己整点活儿新 “物料”。 不管是和奥特曼 “面对面” 聊天还是 “无中生有” 表情包,AI 都能做! (※…

spring boot 热部署

相信小伙伴们在日常的开发中,调试代码时,免不了经常修改代码,这个时候,为了验证效果,必须要重启 Spring Boot 应用。 频繁地重启应用,导致开发效率降低,加班随之而来。有没有什么办法&#xff0…

宏电股份受邀参加中国联通战新共创启航大会,共筑产业生态,链通数智未来

11月21日,由中国联通举办的主题为“共筑产业生态,链通数智未来”的网络安全现代产业链共链行动计划暨战新共创启航大会“5G工业互联网”专题供需对接会在北京顺利召开,宏电股份董事长左绍舟应邀出席活动。 会议现场,中国联通雁飞…

Rust开发——数据对象的内存布局

枚举与Sized 数据 一般数据类型的布局是其大小(size)、对齐方式(align)及其字段的相对偏移量。 1. 枚举(Enum)的布局: 枚举类型在内存中的布局通常是由编译器来确定的。不同的编译器可能有不…

centos7 系统keepalived 定时执行脚本

安装keepalived yum install -y keepalived 修改配置文件 配置文件路径 /etc/keepalived 配置文件内容 global_defs {router_id localhost.localdomain # 访问到主机,本机的hostname,需要修改 }vrrp_script chk_http_port {script "/etc/kee…

INFLOW:用于检测隐藏服务器的反向网络流水印

文章信息 论文题目:INFLOW: Inverse Network Flow Watermarking for Detecting Hidden Servers 期刊(会议):IEEE INFOCOM 2018 - IEEE Conference on Computer Communications 级别:CCF A 文章链接:https:…

Docker 安装 Apache

目录 拉取官方 Apache 镜像 查看本地镜像 列出正在运行的容器 运行 Apache 容器 创建一个 HTML 文件:index.html 访问 Apache 拉取官方 Apache 镜像 查找 Docker Hub 上的 httpd 镜像。 可以通过 Tags 查看其他版本的 httpd,默认是最新版本 httpd…

SpringMVC 基础知识

学习目标 掌握基于 SpringMVC 获取请求参数与响应 json 数据操作熟练应用基于 REST 风格的请求路径设置与参数传递能够根据实际业务建立前后端开发通信协议并进行实现基于 SSM 整合技术开发任意业务模块功能 1 SpringMVC 简介 1.1 概述 1.1.1 web程序开发流程 【执行过程】…