深入解析HashMap:结构与哈希函数揭秘一

文章目录

  • 一、HashMap的基本结构
    • 1.数组与链表的结构
      • 1.1 数组
      • 1.2 链表
    • 2.红黑树的简单介绍
    • 3.Node节点的组成
  • 二、HashMap的哈希函数
    • 1.hashCode()方法的作用
    • 2.位运算与哈希值的计算
    • 3.扰动函数的作用
  • 思考:为什么HashMap源码中使用位运算

在Java编程语言中,HashMap是一个至关重要的数据结构,它提供了键值对存储的高效方式。对于开发者来说,了解HashMap的内部工作原理不仅能够帮助提升编程技能,还能在实际应用中更好地利用这种数据结构。本文是“HashMap源码解析”的第一部分,我们将深入探讨HashMap的结构、哈希函数以及碰撞处理机制。

一、HashMap的基本结构

1.数组与链表的结构

1.1 数组

是一个线性表数据结构,它用一组连续的内存空间来存储一组具有相同类型的数据结构。

特点:

  • 静态数据结构:数组在创建时就有固定的大小,一旦创建,其大小不可改变。
  • 每一个元素都有索引,且是连续的,通过索引下标查询数据时间复杂度为O(1)。故,查询快~
  • 数组的大小是固定的,所以当数组需要插入、删除时,就涉及到了扩容,Java中数组是不支持动态扩容的。故,插入、删除慢~
  • 边界检查:Java数组在访问元素时会进行边界检查,如果越界,会抛出ArrayIndexOutOfBoundsException。

1.2 链表

一系列节点组成的集合,不要求连续的内存空间,每个节点存储着指向下个节点的引用

特点:

  • 不是连续的内存空间存储,查询时需要遍历全链表。故,查询慢O(n)~但是如果查询头节点、尾节点,可以直接通过方法获取O(1)
  • 链表的长度不是固定的,可以动态增加或减少
  • 链表插入或删除数据的时候,可以通过改变节点的指针实现。故,插入、删除快~时间复杂度O(1)
  • 无边界检查:链表不进行边界检查,访问节点时不会抛出ArrayIndexOutOfBoundsException。

2.红黑树的简单介绍

是一个黑色完美平衡的二叉树,即任意节点到每个叶子节点路径中黑色节点的数量相同,这一特性又称黑高

特点

  • 节点要么是红色,要么是黑色
  • 两个红色节点不能相连
  • 根节点一定是黑色的
  • 黑高
  • 每个叶子节点(NIL)是黑色的
    在这里插入图片描述

3.Node节点的组成

  • final int hash; # 节点键的hash值,HashMap使用这个哈希值来快速定位数组的索引,存储和检索键值对
  • final K key; # 节点key,键是唯一标识,用于获取值
  • V value; # 节点键对应的值
  • Node<K,V> next; # 节点指向的下一个节点
    static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;

        Node(int hash, K key, V value, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }

        public final K getKey()        { return key; }
        public final V getValue()      { return value; }
        public final String toString() { return key + "=" + value; }

        public final int hashCode() {
            return Objects.hashCode(key) ^ Objects.hashCode(value);
        }

        public final V setValue(V newValue) {
            V oldValue = value;
            value = newValue;
            return oldValue;
        }

        public final boolean equals(Object o) {
            if (o == this)
                return true;

            return o instanceof Map.Entry<?, ?> e
                    && Objects.equals(key, e.getKey())
                    && Objects.equals(value, e.getValue());
        }
    }

二、HashMap的哈希函数

1.hashCode()方法的作用

  • hashCode()是Object类的方法
  • 通过hashCode()方法可以进行字符串加密生成哈希码,且不可逆。通过哈希码确定键值对的位置

理想情况下,hashCode()方法应该为不同的对象生成不同的哈希码,以减少哈希冲突的概率。然而,在实际应用中,可能会出现不同的对象产生相同哈希码的情况,这种现象称为哈希冲突。为了处理哈希冲突,HashMap使用了链表和红黑树的数据结构来存储具有相同或相近哈希码的键值对。

2.位运算与哈希值的计算

在HashMap的源码中大量用到了位运算与运算的地方。
在HashMap中,hashCode()方法返回的哈希码通常是一个整型值。为了将这个哈希码转换成内部数组的索引,HashMap使用了位运算。

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

这里的^是按位异或运算符,>>>是无符号右移运算符。
这种运算可以确保哈希码的高位和低位都被用于索引的计算,从而减少哈希冲突的概率。

3.扰动函数的作用

HashMap的hash方法用于计算键的哈希码,并将其转换为哈希表的索引。这个方法确实使用了位运算来扰动哈希码,但是具体的实现稍微有所不同。

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

这个方法会首先计算键的哈希码h(h = key.hashCode()),然后将其无符号右移16位(h >>> 16),并与原始哈希码进行异或运算。这样做的目的是将高位的特征和低位的特征混合起来,以减少哈希冲突
然而,这个扰动的哈希码并不直接用作数组的索引。在Java 8中,HashMap的数组长度必须是2的幂,因此数组的索引是通过下面的方式计算的:

(n - 1) & hash

这里的n是数组的长度,hash是上面计算的扰动哈希码。(n - 1)是一个所有位都是1的二进制数(例如,如果n是16,那么(n - 1)0b1111),这样做的效果是取模运算,但是位运算通常比模运算快得多。
在Java 8中,还有一个重要的优化,当链表的长度超过一定阈值时,链表会转换为红黑树,以提高性能。

思考:为什么HashMap源码中使用位运算

在HashMap中使用位运算是为了提高哈希分布的均匀性,减少哈希冲突的概率,从而提高整体的性能。以下是使用位运算的几个原因:

  1. 速度:位运算通常比其他数学运算要快,因为它们直接在数字的二进制表示上操作,而现代计算机的CPU对位运算有直接的硬件支持。
  2. 均匀分布:通过位运算,可以将哈希码的高位和低位混合,从而使得哈希码的每个位都对最终的索引结果产生影响。这样可以减少哈希码中某些位总是为零或总是为一的情况,使得哈希值更加均匀地分布在哈希表中。
  3. 减少哈希冲突:哈希冲突是指两个不同的键产生了相同的哈希值。通过位运算,可以增加哈希值的独特性,减少冲突的可能性。
  4. 适应不同容量:HashMap的容量通常是2的幂次方,使用位运算可以很容易地计算出哈希值在哈希表中的位置。例如,如果哈希表的容量是2^n,那么可以通过hash & (2^n - 1)来计算索引,这里的&是按位与运算符,它等价于hash % 2^n,但执行速度更快。
  5. 利用CPU缓存:现代CPU缓存行通常是一次性加载一块数据,而位运算可以帮助优化数据的内存布局,使得哈希表中的元素更可能被加载到同一缓存行中,从而提高缓存利用率。

在HashMap中,扰动函数通常包括将哈希码的高16位与低16位进行异或运算,这样可以确保哈希码的每个位都对索引结果有影响,从而提高哈希表的性能。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Docker进阶:深入了解 Dockerfile

Docker进阶&#xff1a;深入了解 Dockerfile 一、Dockerfile 概述二、Dockerfile 优点三、Dockerfile 编写规则四、Dockerfile 中常用的指令1、FROM2、LABEL3、RUN4、CMD5、ENTRYPOINT6、COPY7、ADD8、WORKDIR9、 ENV10、EXPOSE11、VOLUME12、USER13、注释14、ONBUILD 命令15、…

解决方案-Windows下cmd输入nvidia-smi命令无效

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 问题描述 nvidia-smi是 NVIDIA System Management Interface 的缩写&#xff0c;是 NVIDIA 提供的用于管理和监控 NVIDIA GPU 设备…

爱普生小体积贴片晶振独特的蚀刻工艺

爱普生EPSON它是全球最大的打印机生产企业也是石英品体元器件生产厂家,品种齐全而且生产工艺也是世界顶尖的企业,不论在制作工艺上还是切割蚀刻工艺技术上都是比较先进的,它的一项千赫兹AT切产品足以让电子行业的人为之钦佩,在2010年发布的全球晶振企业排行榜爱普生占据首位,以…

IDEA管理Git + Gitee 常用操作

文章目录 IDEA管理Git Gitee 常用操作1.Gitee创建代码仓库1.创建仓库1.点击新建仓库2.完成仓库信息填写3.创建成功4.管理菜单可以修改这个项目的设置 2.设置SSH公钥免密登录基本介绍1.找到.ssh目录2.执行指令 ssh-keygen3.将公钥信息添加到码云账户1.点击设置2.ssh公钥3.复制.…

挖到宝了!这几款AI知识库原来这么好用!

随着人工智能的发展&#xff0c;我们的工作和生活越来越依赖这些智能化的工具。其中&#xff0c;AI知识库已经成为我们管理和获取知识的重要工具之一。今天我要为大家推荐三款好用的AI知识库&#xff0c;无论你是企业用户还是个人用户&#xff0c;相信一定能找到你心仪的那一个…

HTML5+CSS3+JS小实例:全屏背景切换动画

实例:全屏背景切换动画 技术栈:HTML+CSS+JS 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-s…

英飞凌电源管理PMIC的安全应用

摘要 本篇文档主要用来介绍英飞凌电源管理芯片TLF35584的使用&#xff0c;基于电动助力转向应用来介绍。包含一些安全机制的执行。 TLF35584介绍 TLF35584是英飞凌推出的针对车辆安全应用的电源管理芯片&#xff0c;符合ASIL D安全等级要求&#xff0c;具有高效多电源输出通道&…

Mysql 死锁案例1-记录锁读写冲突

死锁复现 CREATE TABLE t (id int(11) NOT NULL,c int(11) DEFAULT NULL,d int(11) DEFAULT NULL,PRIMARY KEY (id),KEY c (c) ) ENGINEInnoDB DEFAULT CHARSETutf8;/*Data for the table t */insert into t(id,c,d) values (0,0,0),(5,5,5),(10,10,10) 事务1事务2T1 START…

msfconsole数据库连接不了的问题【已解决】

msfconsole数据库连接 1.msf数据库端口 msf使用的是postgresql&#xff0c;这个数据库默认端口是5432 单个模块的使用可以不需要数据库&#xff0c;但是模块与模块之间需要沟通的时候就会用到数据库。 2.查看msf数据库连接状态 db_status #msf内部查看systemctl status p…

基于逻辑回归与决策树的地质灾害预测

大家好&#xff0c;我是带我去滑雪&#xff01; 地质灾害的预测对于人们的生命财产安全、社会稳定和经济发展具有重要意义。地质灾害如地震、泥石流、山体滑坡等往往会造成严重的人员伤亡和财产损失。大规模的地质灾害往往会导致社会秩序混乱、人员流动、灾民避难等问题&#x…

深度学习技巧总结

1、监控GPU使用情况 pip install nvitopnvitop -m fullhttps://zhuanlan.zhihu.com/p/577533593 2、本地拉取服务器上tensorboard数据并进行可视化显示 https://blog.csdn.net/Thebest_jack/article/details/125609849 3、服务器打不开pycharm软件 这个是已经有一个软件在运…

docker部署开源多功能监控系统

HertzBeat 是一个无需 Agent、高性能、易扩展、功能强大的开源实时监控告警系统&#xff0c;无需 Agent、高性能、易扩展、功能强大&#xff0c;由 Dromara 团队开发并开源&#xff0c;能够帮我们轻松监控应用、服务、基础设施等各种资源的运行状况 部署 docker run -d -p 11…

1.Spring核心功能梳理

概述 本篇旨在整体的梳理一下Spring的核心功能,让我们对Spring的整体印象更加具体深刻,为接下来的Spring学习打下基础。 本片主体内容如下: Bean的生命周期依赖注入的实现Bean初始化原理推断构造方法原理AOP的实现这里要说明一下,我们这里说到的Spring,一般指的是Spring F…

rust 正在全面入侵前端

公众号&#xff1a;程序员白特&#xff0c;欢迎一起交流学习~ 原文作者&#xff1a;这波能反杀 过年期间我没怎么发文章&#xff0c;但是我也没闲着。在这个空闲时间&#xff0c;把 rust 基础以及个别生态技术方案扎扎实实的&#xff0c;系统的学习了一下。学习他的初衷是因为 …

5G“升级版”:5G-A正当其时

5G商用五年来&#xff0c;全球5G用户规模已经突破15亿&#xff0c;相当于4G九年的发展成果&#xff1b;同时&#xff0c;5G用20%的全球移动用户占比&#xff0c;贡献了30%的移动流量与40%的移动业务收入。而2月26日-29日在西班牙巴塞罗那举办的世界移动通信大会&#xff08;MWC…

Vue+wow.js+animate.css实现动画效果

1.介绍 Wow.js 是一个轻量级的 JavaScript 库&#xff0c;用于在网页滚动时实现动画效果。基于 CSS3 的动画库 Animate.css&#xff0c;并通过触发 CSS 动画类来创建各种引人注目的过渡和动画效果。 使用 Wow.js&#xff0c;可以很容易地为网页中的元素添加动画效果&#xff…

Redis持久化和集群

redis持久化 RDB方式 Redis Database Backup file (redis数据备份文件), 也被叫做redis数据快照. 简单来说就是把内存中的所有数据记录到磁盘中. 快照文件称为RDB文件, 默认是保存在当前运行目录. [rootcentos-zyw ~]# docker exec -it redis redis-cli 127.0.0.1:6379> sav…

供应IMX290LQR-C芯片现货

长期供应各品牌芯片现货&#xff0c;SONY索尼SONY索尼CMOS/CCD芯片全系列全新现货优势出&#xff1a; IMX225LQR-C IMX415-AAQR-C IMX290LQR-C imx273llr-C IMX397CLN-C IMX637-AAMJ-C IMX647-AAMJ-C IMX991-A***-C IMX991-AABJ-C IMX287LLR-C IMX287LQR-C IMX297L…

Pygame教程06:Event事件的类型+处理方法+监听鼠标事件

------------★Pygame系列教程★------------ Pygame教程01&#xff1a;初识pygame游戏模块 Pygame教程02&#xff1a;图片的加载缩放旋转显示操作 Pygame教程03&#xff1a;文本显示字体加载transform方法 Pygame教程04&#xff1a;draw方法绘制矩形、多边形、圆、椭圆、弧…

「璞华精选」品牌展区成为亮点,引领海外优质生活新潮流!

展会概况 3月07-09日&#xff0c;CCF 2023上海春季百货展在上海新国际博览中心圆满收官。以“聚焦品牌引流行业”为定位目标的CCF上海国际日用百货&#xff08;春季&#xff09;博览会&#xff0c;立足上海&#xff0c;辐射全球商贸&#xff0c;链接行业市场全局&#xff0c;赋…
最新文章