[HashMap源码学习之路]---hashcode的作用及数组长度为什么是2的n次幂

2023-11-17

HashMap中的hashcode作用

  HashMap是Java 中很重要的一个概念,工作中使用的频率也非常广泛,需要对其进行了解。
  看源码是很枯燥的,但是看懂了,却有种豁然开朗的感觉,觉得特别棒,本篇只说hashcode的作用及数组长度为什么是2的n次幂
  首先点开HashMap的类,我是用开发工具idea ,新建了一个HashMap,点进去找到put方法。以jdk 1.8为例,如下:

public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

  然后再点进putVal 方法,则会看到有下面的代码:

tab[i = (n - 1) & hash]

1、HashMap 中为什么需要一个hashCode 值?

  原因就是需要用它来对HashMap 数组的位置来定位,如果向HashMap 里存一个数,单纯的依次使用equals 方法比较key 是否相同来确定当前数据是否已存储过,那效率非常低,而通过比较hashCode 值,效率就会大大提高,那它是如何定位数组位置呢,如果你使用的是jdk 1.8,那在put方法中的putVal方法里会看到如下内容:

  对于上边的n-1 后边会说到,先说一下上边的写法,& 为二进制中的与运算 ,它的运算特点是,两个数进行& ,如果都为1,则运算结果为1,否则为0。
  因为hashMap 的数组长度都是2的n次幂 ,那么对于这个数再减去1,转换成二进制的话,就肯定是最高位为0,其他位全是1 的数,那以数组长度为8为例(默认HashMap初始数组长度是16),那8-1 转成二进制的话,就是0111
  那我们举一个随便的hashCode值,与0111 进行与运算 看看结果如何,如下:

 第一个key:      hashcode值:10101000    
   与0111进行&运算        &       0111                                      
                                 0000  (十进制为0)
   ------------------------------------------               
 第二个key:      hashcode值:11101000    
   与0111进行&运算        &       0111      
                                 0000  (十进制为0)
 --------------------------------------------               
 第三个key:      hashcode值:11101010    
   与0111进行&运算        &       0111      
                                 0010  (十进制为2)

  你可以随便变hashcode 值来测试,最终得到的数都会小于8 ,当然会像上边一样,出现相同的数据,那样的话,就会以链表的形式存在那个数组元素上了。
  回过头来再设想一下,那我们就可以通过把key转为hashCode值,然后与数组长度进行与运算 ,来确定HahsMap 中当前key对应的数据在数组中的位置
  原本,需要查找数组下的每个元素,以及他们对应的链,疯狂的调用equals 方法,誓死遍历出数据的方式,变成了仅仅是查找数组下的一个元素,然后,只需要equals 比较这一条链上的数据就可以了,这样equals 的使用次数降低了很多。
  通过上边的说明,不知道大家是否理解到了hashCode 值,在HashMap 中的作用呢?

2、为什么hashMap 的数组长度为2的n次幂

  还是上边那行代码:

tab[i = (n - 1) & hash]

  我们知道了& 的作用,但是n-1 到底是什么意思呢?
其实上边,已经提到过了,就是2的n次幂 是很特殊的数,随便满足这个条件的数,对它减去1,转换成二进制,都会有这样的特点,即,最高位为0,其他低位全为1
  就以数组长度分别为87 为例,看下边的情况:

数字8减去1转换成二进制是0111,即下边的情况
 第一个key:      hashcode值:10101001    
   与0111进行&运算        &       0111                                      
                                 0001  (十进制为1)
   ------------------------------------------                           
 第二个key:      hashcode值:11101000    
   与0111进行&运算        &       0111      
                                 0000  (十进制为0)
--------------------------------------------               
 第三个key:      hashcode值:11101110    
   与0111进行&运算        &       0111      
                                 0110  (十进制为6)

  这样得到的数,就会完整的得到原hashcode 值的低位值,不会受到与运算对数据的变化影响。

数字7减去1转换成二进制是0110,即下边的情况
 第一个key:      hashcode值:10101001    
   与0111进行&运算        &       0110                                      
                                 0000  (十进制为0)
   ------------------------------------------                           
 第二个key:      hashcode值:11101000    
   与0111进行&运算        &       0110      
                                 0000  (十进制为0)
--------------------------------------------               
 第三个key:      hashcode值:11101110    
   与0111进行&运算        &       0111      
                                 0110  (十进制为6)

  通过上边可以看到,当数组长度不为2的n次幂 的时候,hashCode 值与数组长度减一做与运算 的时候,会出现重复的数据,因为不为2的n次幂 的话,对应的二进制数肯定有一位为0 ,这样,不管你的hashCode 值对应的该位,是0 还是1 ,最终得到的该位上的数肯定是0 ,这带来的问题就是HashMap 上的数组元素分布不均匀,而数组上的某些位置,永远也用不到。如下图所示:
这里写图片描述
  这将带来的问题就是你的HashMap 数组的利用率太低,并且链表可能因为上边的(n - 1) & hash 运算结果碰撞率过高,导致链表太深。(当然jdk 1.8已经在链表数据超过8个以后转换成了红黑树的操作,但那样也很容易造成它们之间的转换时机的提前到来)。
  以上即是我理解的HashMap这方面的知识。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[HashMap源码学习之路]---hashcode的作用及数组长度为什么是2的n次幂 的相关文章

随机推荐

  • [人工智能-深度学习-17]:神经网络基础 - 优化算法的本质是盲人探路或迷雾探险

    作者主页 文火冰糖的硅基工坊 文火冰糖 王文兵 的博客 文火冰糖的硅基工坊 CSDN博客 本文网址 https blog csdn net HiWangWenBing article details 120591591 目录 第1章 los
  • 使用PHPMailer发送邮件

    设置邮箱 所有的主流邮箱都支持 SMTP 协议 但并非所有邮箱都默认开启 您可以在邮箱的设置里面手动开启 第三方服务在提供了账号和密码之后就可以登录 SMTP 服务器 通过它来控制邮件的中转方式 SMTP 服务器认证密码 需要妥善保管 加载
  • 常见(但不常见)单子

    上周 我们研究了monad如何帮助您实现Haskell开发的下一个跃进 我们讨论了runXXXT模式 以及如何使用其余代码中的某些monad作为通用网关 但是有时它也有助于回到基础知识 实际上 我花了很长时间才真正掌握如何使用几个基本的mo
  • JUnit->Mockito->PowerMock->持续更新

    最近在公司做需求 要求开发需要有相应的单元测试代码 第一次做单测相关的知识 就在这做一篇总结 一 JUnit JUnit是Java最基础的测试框架 主要的作用就是断言 方法名 方法描述 assertEquals 断言传入的预期值与实际值是相
  • 求救,在频域分析语音信号谐波成分的方法有哪些

    求救 在频域分析语音信号谐波成分的方法有哪些 有一段语音信号 经过FFT之后变换到频域 目前想在频域分析其谐波成分 并找到谐波能量最大的K次谐波 matlab里可以用仿真powergui生成仿真的信号 然后FFT分析得到各谐波成分及能量 但
  • vi命令修改文件及保存的使用方法

    简单点 vi文件名 按 I 进入insert模式 可以正常文本编辑 编辑好之后按 esc 退出到 命令模式 再按 shift 进入 底行模式 按 wq 保存退出 还一种 把文件复制到本地修改好上传上去 vi编辑器是所有Unix及Linux系
  • 每日一练:用java打印水仙花数

    需求 在控制台输出所有的 水仙花数 解释 什么是水仙花数 水仙花数 指的是一个三位数 个位 十位 百位的数字立方和等于原数 例如153 3 3 3 5 5 5 1 1 1 153 思路 获取所有的三位数 准备进行筛选 最小的三位数为100
  • cp1.php969.net,eDrawings

    OzsgSFNGIFYxMy4wNSAKSQAAAABCAGDlUL0Spb29AAAAAGXlUD13vp89x0rNPVp42uy9B0AUSdMw3LMzsxHYJeec8 6SdoGVJagoiAFBMAOimNDDhBHMeqen
  • 怎么批量安装服务器的操作系统,批量安装服务器操作系统

    弹性云服务器 ECS 弹性云服务器 Elastic Cloud Server 是一种可随时自助获取 可弹性伸缩的云服务器 帮助用户打造可靠 安全 灵活 高效的应用环境 确保服务持久稳定运行 提升运维效率 三年低至5折 多种配置可选了解详情
  • 数组(持续更新后续)

    目录 数组定义 数组的组成部门 案例一 案例二 案例三 增强for循环 语法结构 执行规律 注意 案例 案例 案例 数组定义 变量 存储数据的空间 装数据的容器 变量中只能存储一个数据 数组 存储数据的空间 装数据的容器 数组中可以存储多个
  • sojson JS 逆向一 (简单版)

    背景 现在市面上很多web网页都是使用sojson加密的 所以 爬虫小伙伴对sojson的学习迫在眉睫 js 加密源码 var a b function w d w info 这是一个一系列js操作 d warning 如果您的JS里嵌套了
  • 202206-3 角色授权

    第三题 题干 角色授权 include
  • svn更新有问题svn: The working copy at' ' is too old

    SVN the working copy needs to be upgraded svn 低版本SVN检出代码 高版本SVN提交不了解决方法如下 项目右键 team Upgrade 即可 如下图 参考URL https blog csdn
  • Python:流动爱心图案

    from turtle import 导入了Python标准库中的turtle模块 并使用通配符 导入了该模块中的所有函数和变量 turtle模块提供了一个绘图窗口和一些绘图函数 可以用来绘制简单的图形 from math import s
  • python-爬虫初识-采集汽车资讯信息案例(一)

    目录 一 什么是爬虫 二 初识爬虫 采集汽车资讯信息 三 requests和BeautifulSoup模块基本使用 requests import requests BeautifulSoup from bs4 import Beautif
  • 数学模型——数学与人类文明的桥梁

    序言 数统治着宇宙 Pythagoras 数学一词在西方源于古希腊语 意思是通过学习获得知识 显然 早期数学涵盖的范围比我们今天要广得多 人类科学发展至今 衍生出生物科学 信息科学 金融学 计算机科学等不胜枚举的领域与分支 而数学模型正是数
  • Word打印或打印预览或另存为PDF时出现“错误!未定义书签!”的解决办法

    出处 http blog sina com cn s blog 5ee0924f0101a05l html 今天在单独打印一份三页的目录Word文档时 所有目录的页码全部变为 错误 未定义书签 很是奇妙 一开始还以为是打印问题 又重新打印了
  • 如何使用Google Compute Engine入门指南快速创建和配置您的云虚拟机实例

    文章目录 步骤1 创建 Google Cloud Platform GCP 账户 步骤2 设置 GCP 项目 步骤3 启用 Google Compute Engine API 步骤4 安装 Google Cloud SDK 步骤5 创建虚拟
  • sql中使用union 或者union all语句时,两边的列的顺序必须保持一致

    sql中使用union 或者union all语句时 两边的列的顺序必须保持一致
  • [HashMap源码学习之路]---hashcode的作用及数组长度为什么是2的n次幂

    HashMap中的hashcode作用 HashMap是Java 中很重要的一个概念 工作中使用的频率也非常广泛 需要对其进行了解 看源码是很枯燥的 但是看懂了 却有种豁然开朗的感觉 觉得特别棒 本篇只说hashcode的作用及数组长度为什