HashMap中哈希算法的关键代码

//重新计算哈希值
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);//key如果是null 新hashcode是0 否则 计算新的hashcode
}
//计算数组槽位
(n - 1) & hash

HashMap的细节我们不谈,只看这个哈希算法的细节(h = key.hashCode()) ^ (h >>> 16)

^按位异或运算,只要位不同结果为1,不然结果为0;
>>> 无符号右移:右边补0

为什么要无符号右移16位后做异或运算

根据上面的说明我们做一个简单演练

将h无符号右移16为相当于将高区16位移动到了低区的16位,再与原hashcode做异或运算,可以将高低位二进制特征混合起来

从上文可知高区的16位与原hashcode相比没有发生变化,低区的16位发生了变化

我们可知通过上面(h = key.hashCode()) ^ (h >>> 16)进行运算可以把高区与低区的二进制特征混合到低区,那么为什么要这么做呢?

我们都知道重新计算出的新哈希值在后面将会参与hashmap中数组槽位的计算,计算公式:(n - 1) & hash,假如这时数组槽位有16个,则槽位计算如下:

仔细观察上文不难发现,高区的16位很有可能会被数组槽位数的二进制码锁屏蔽,如果我们不做刚才移位异或运算,那么在计算槽位时将丢失高区特征

也许你可能会说,即使丢失了高区特征不同hashcode也可以计算出不同的槽位来,但是细想当两个哈希码很接近时,那么这高区的一点点差异就可能导致一次哈希碰撞,所以这也是将性能做到极致的一种体现

使用异或运算的原因

异或运算能更好的保留各部分的特征,如果采用&运算计算出来的值会向1靠拢,采用|运算计算出来的值会向0靠拢

为什么槽位数必须使用2^n

1、为了让哈希后的结果更加均匀

这个原因我们继续用上面的例子来说明

假如槽位数不是16,而是17,则槽位计算公式变成:(17 - 1) & hash

从上文可以看出,计算结果将会大大趋同,hashcode参加&运算后被更多位的0屏蔽,计算结果只剩下两种0和16,这对于hashmap来说是一种灾难

2、可以通过位运算e.hash & (newCap - 1)来计算,a % (2^n) 等价于 a & (2^n - 1)  ,位运算的运算效率高于算术运算,原因是算术运算还是会被转化为位运算

说了这么多点,上面提到的所有问题,最终目的还是为了让哈希后的结果更均匀的分部,减少哈希碰撞,提升hashmap的运行效率

HashMap中的hash算法中的几个疑问的更多相关文章

  1. HashMap中的hash算法总结

    前言 算法一直是我的弱项,然而面试中基本是必考的项目,刚好上次看到一个HashMap的面试题,今天也来学习下 HashMap中的hash算法是如何实现的. 数学知识回顾 << : 左移运算 ...

  2. 【Java深入研究】11、深入研究hashmap中的hash算法

    一.简介 大家都知道,HashMap中定位到桶的位置 是根据Key的hash值与数组的长度取模来计算的. JDK8中的hash 算法: static final int hash(Object key ...

  3. 图像相似度中的Hash算法

           度量两张图片的相似度有许多算法,本文讲介绍工程领域中最常用的图片相似度算法之一--Hash算法.Hash算法准确的说有三种,分别为平均哈希算法(aHash).感知哈希算法你(pHash) ...

  4. PHP中各种Hash算法性能比较

    国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...

  5. php中各种hash算法的执行速度比较

    更多内容推荐微信公众号,欢迎关注: PHP中的Hash函数很多,像MD4.MD5.SHA-1.SHA-256.SHA-384.SHA-512等我们比较常见,那么各个哈希的执行速度呢? $algos = ...

  6. Java面试题之hashmap中用什么hash算法解决碰撞的?

    查了一下源码(jdk8),记录一下吧,能记住就记一下吧! static final int hash(Object key) { int h; return (key == null) ? 0 : ( ...

  7. [区块链] 密码学中Hash算法(基础)

    在介绍Hash算法之前,先给大家来个数据结构中对hash表(散列表)的简单解释,然后我再逐步深入,讲解一下hash算法. 一.Hash原理——基础篇 1.1 概念 哈希表就是一种以 键-值(key-i ...

  8. hash算法与hashmap

    参考博客: http://zha-zi.iteye.com/blog/1124484 http://www.cnblogs.com/dolphin0520/p/3681042.html(参考了hash ...

  9. STL中的查找算法

    STL中有很多算法,这些算法可以用到一个或多个STL容器(因为STL的一个设计思想是将算法和容器进行分离),也可以用到非容器序列比如数组中.众多算法中,查找算法是应用最为普遍的一类. 单个元素查找 1 ...

随机推荐

  1. 通过Chrome扩展来批量复制知乎好友

        1.初始化文件 Chrome 官方扩展教程地址 新建一个文件夹 zhi-follow 下图中 1 部分为 默认的图标3种尺寸 会显示在 Chrome 中   2. 定义按钮样式   页面上会有 ...

  2. 浏览器禁用cookie后php如何保持session会话-use_trans_sid机制

    原文:浏览器禁用cookie后php如何保持session会话-use_trans_sid机制 为防止浏览器禁用cookie导致服务器会话无法保持,php开发了一个机制,该机制开启后,浏览器发起请求后 ...

  3. 关于 Apache 2.4 配置PHP时的错误记录

    1. 访问虚拟配置的站点抛出 Forbidden 403 错误 解决办法: <Directory E:/Xingzhi/Php/xingzhi.xingzhi.com/>     Opti ...

  4. 数据库连接池之_Druid简单使用

    数据库连接池: 连接池是创建和管理一个连接的缓冲池的技术,这些连接真备好被任何需要他们的线程使用,可以对传统的JDBCjava数据库连接()进行优化 在实际开发中,我们需要频繁的操作数据库,这就意味着 ...

  5. Qt常见皮肤qss代码(有Metro的风格)

    ##QTabWidget 淡蓝色效果TabWidget(属性值lightblue) QTabWidget[lightblue = "true"] QTabBar::tab{ bor ...

  6. 使用AnimateWindow来实现窗口淡入淡出(主要有四种动画,滚动,滑动,折叠或展开,和淡入淡出)

    如果是在VC6下进行编译,应引入下面的预编译宏,注意放在windows.h的前面#undef  WINVER   #define  WINVER   0x500为什么要引入上面的宏呢?看看winuse ...

  7. 教你如何在 Visual Studio 2013 上使用 Github

    介绍 我承认越是能将事情变简单的工具我越会更多地使用它.尽管我已经知道了足够的命令来使用Github,但我宁愿它被集成到IDE中.在本教程中,我会告诉你使用Visual Studio 2013如何实现 ...

  8. [2017.02.21-22] 《Haskell趣学指南 —— Learning You a Haskell for Great Good!》

    {- 2017.02.21-22 <Haskell趣学指南 -- Learning You a Haskell for Great Good!> 学习了Haskell的基本语法,并实现了一 ...

  9. Python自学day-8

    一.SocketServer 简化了编写网络服务器的难度. SocketServer一共有如下几个类型: socketserver.TCPServer :提供一个TCP的socketserver. s ...

  10. spring 5.x 系列第21篇 —— spring 定时任务 (xml配置方式)

    源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all 一.说明 1.1 项目结构说明 关于任务的调度配置定义在springApp ...