大家都知道(jdk1.8)HashMap中计算数组下标是HashMap的核心算法。小编今天在看HashMap源码中看到了hash(Object key)方法百思不得其解。小编问百度,查找相关博客,甚至连HashMap的关于hash(Object key)英文解释都看了。但是都只是说了为了尽量均匀,没有详细讲。小编今天为大家详细讲解一下这两个问题。

HashMap中hash(Object key)的原理,为什么这样做?

先看下hash(Object key)方法,详细大家基本都能看懂,但是知道这一步(h = key.hashCode()) ^ (h >>> 16)原因的人很少。

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

首先这个方法的返回值还是一个哈希值。为什么不直接返回key.hashCode()呢?还要与 (h >>> 16)异或。首先要了解以下知识点:

必备知识点.:^ 运算  >>>运算  &运算。

1. h >>> 16 是什么,有什么用?

h是hashcode。h >>> 16是用来取出h的高16,(>>>是无符号右移)   如下展示:

0000 0100 1011 0011  1101 1111 1110 0001>>> 16 0000 0000 0000 0000  0000 0100 1011 0011

2. 为什么 h = key.hashCode()) 与 (h >>> 16) 异或

讲到这里还要看一个方法indexFor,在jdk1.7中有indexFor(int h, int length)方法。jdk1.8里没有,但原理没变。下面看下1.7源码

1.8中用tab[(n - 1) & hash]代替但原理一样。

 
static int indexFor(int h, int length) {return h & (length-1);
}

这个方法返回值就是数组下标。我们平时用map大多数情况下map里面的数据不是很多。这里与(length-1)相&,

但由于绝大多数情况下length一般都小于2^16即小于65536。所以return h & (length-1);结果始终是h的低16位与(length-1)进行&运算。如下例子(hashcode为四字节)

例如1:为了方便验证,假设length为8。HashMap的默认初始容量为16

length = 8;  (length-1) = 7;转换二进制为111;

假设一个key的 hashcode = 78897121 转换二进制:100101100111101111111100001,与(length-1)& 运算如下

 
    0000 0100 1011 0011 1101 1111 1110 0001&运算0000 0000 0000 0000 0000 0000 0000 0111=   0000 0000 0000 0000 0000 0000 0000 0001 (就是十进制1,所以下标为1)

​​​​​​​上述运算实质是:001 与 111 & 运算。也就是哈希值的低三位与length与运算。如果让哈希值的低三位更加随机,那么&结果就更加随机,如何让哈希值的低三位更加随机,那么就是让其与高位异或。

补充知识:

当length=8时    下标运算结果取决于哈希值的低三位

当length=16时  下标运算结果取决于哈希值的低四位

当length=32时  下标运算结果取决于哈希值的低五位

当length=2的N次方, 下标运算结果取决于哈希值的低N位。

3. 原因总结

由于和(length-1)运算,length 绝大多数情况小于2的16次方。所以始终是hashcode 的低16位(甚至更低)参与运算。要是高16位也参与运算,会让得到的下标更加散列。

所以这样高16位是用不到的,如何让高16也参与运算呢。所以才有hash(Object key)方法。让他的hashCode()和自己的高16位^运算。所以(h >>> 16)得到他的高16位与hashCode()进行^运算。

4. 为什么用^而不用&和|

因为&和|都会使得结果偏向0或者1 ,并不是均匀的概念,所以用^。

这就是为什么有hash(Object key)的原因。

下一遍,小编为大家讲解为什么HashMap数组长度是2的幂次方(2^n)。

补充:在length小的时候,只是低16位(甚至更小)参与于运算,运算结果取决于哈希值的低位,如78897121 的哈希值0000 0100 1011 0011 1101 1111 1110 0001。与length与运算结果取决于哈希值的低3位。也就是001,001&111 -> 001。如果让哈希值的低3位001变得更加随机那么只需要和高位^,就可以让刚刚的哈希值的低3位更加随机。让高位参与运算是为了让哈希值的低位更加随机,这样计算出来的下标才更加随机,散列。

转自:https://blog.csdn.net/qq_42034205/article/details/90384772

HashMap中hash(Object key)原理(hashcode >>> 16)相关推荐

  1. HashMap中hash(Object key)原理,为什么(hashcode >>> 16)。

    未经本人容许,禁止转载 大家都知道(jdk1.8)HashMap中计算数组下标是HashMap的核心算法.小编今天在看HashMap源码中看到了hash(Object key)方法百思不得其解.小编问 ...

  2. Java中hashCode()方法以及HashMap()中hash()方法

    Java的Object类中有一个hashCode()方法: public final native Class<?> getClass(); public native int hashC ...

  3. HashMap中hash函数怎么是实现的?

    我们可以看到,在 hashmap 中要找到某个元素,需要根据 key 的 hash 值来求得对应数组中的位置.如何计算这个位置就是 hash 算法. 前面说过,hashmap 的数据结构是数组和链表的 ...

  4. hash算法_阿里面试官:讲一下Hashmap中hash算法!

    注:本文内容全部基于jdk8讲述. 相信很多人都知道,在JDK8中,HashMap的容量总是2的n次幂,那么这么设计的目的究竟是什么呢?我可不可以将默认的初始容量从16改成20呢,扩容的时候我可不可以 ...

  5. mysql的hash分区_MySQL中hash和key分区值的计算方法

    MySQL中hash和key分区值的计算方法 mysql中有一种叫作key作为partition key的类型.来看看记录是怎么分布的 对于hash 分区,使用%操作符,每个partition key ...

  6. [Java 8 HashMap 详解系列]7.HashMap 中的红黑树原理

    [Java 8 HashMap 详解系列] 文章目录 1.HashMap 的存储数据结构 2.HashMap 中 Key 的 index 是怎样计算的? 3.HashMap 的 put() 方法执行原 ...

  7. HashMap 中 hash 冲突的解决方法及原理分析

    我们最先衰老的不是容貌,而是不顾一切的闯劲.有时候,要敢于背上超出自己预料的包袱,真的努力后,你会发现自己要比想象的优秀很多. HashMap冲突的解决方法比较考验一个开发者解决问题的能力. 在Jav ...

  8. String中的hashcode缓存以及HashMap中String作key的好处

    目录 hashcode方法源码 不可变性 缓存HashCode 线程安全 hashcode方法源码 public int hashCode() {int h = hash;if (h == 0 &am ...

  9. hashmap中的key是有序的么_HashMap?面试?我是谁?我在哪

    (给ImportNew加星标,提高Java技能) 转自:卓庆森 https://www.cnblogs.com/zhuoqingsen/p/8577646.html 现在是晚上11点了,学校屠猪馆的自 ...

最新文章

  1. 面对万亿级测序市场,纳米孔测序技术何去何从?
  2. xmpp with openfire之一 xmpp and openfire
  3. 3.12 总结-深度学习第二课《改善深层神经网络》-Stanford吴恩达教授
  4. Tableau实战系列Tableau基础概念全解析 (二)-万字长文解析数据类型及数据集
  5. 测试手机信号格数软件,超详细教程之教你如何查询手机信号的强度
  6. 深入剖析js命名空间函数namespace
  7. linux伙伴系统算法,Linux伙伴系统(三)--分配
  8. 改善 Python 程序的 91 个建议
  9. Java类类getGenericSuperclass()方法及示例
  10. Solr.NET快速入门(七)【覆盖默认映射器,NHibernate集成】
  11. gem ruby on rails 安装出错GemNotFoundException
  12. 绘制卡方分布的概率密度函数 matlab,MATLAB如何使用chi2pdf函数计算卡方分布的概率密度...
  13. Android调用长截屏,Android实现长截屏功能
  14. 周鸿祎创业史细说漫谈话神秘
  15. 代码里的Override和Overload
  16. 【简答题】JavaWeb必问10道简答题
  17. 关于D4RL的agent包的tf.contrib兼容性问题
  18. Supervisor使用简介
  19. ros使用usb摄像头追踪ArUco markers
  20. selenium抓取斗鱼直播平台数据

热门文章

  1. windows xp 创建 Oracle(11G)数据库实例时写入系统日志失败解决方案
  2. apache2.2:使一个目录允许执行cgi程序
  3. tar (child): lbzip2: Cannot exec: No such file or directory 解决方法
  4. ubuntu12.04 android studio 安装
  5. dos命令行设置网络优先级_网络安全之木马病毒的防范以及攻击
  6. Java 匿名内部类解析
  7. mysql 使用select建表_mysql create创建表、insert into插入数据、select查询数据实例
  8. JDK 9 中有哪些 jmod 文件?
  9. Struts2之初识篇(一)——与struts的区别和基本配置
  10. 国内开源社区软件 PHPWind 团队已解散