/**
* Computes key.hashCode() and spreads (XORs) higher bits of hash
* to lower. Because the table uses power-of-two masking, sets of
* hashes that vary only in bits above the current mask will
* always collide. (Among known examples are sets of Float keys
* holding consecutive whole numbers in small tables.) So we
* apply a transform that spreads the impact of higher bits
* downward. There is a tradeoff between speed, utility, and
* quality of bit-spreading. Because many common sets of hashes
* are already reasonably distributed (so don't benefit from
* spreading), and because we use trees to handle large sets of
* collisions in bins, we just XOR some shifted bits in the
* cheapest possible way to reduce systematic lossage, as well as
* to incorporate impact of the highest bits that would otherwise
* never be used in index calculations because of table bounds.
*/
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

上次在面试中被问及一个问题:如果直接拿key的内存地址的long值与table的长度做取余操作(%),有什么不好?

我做了一番研究。

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

首先,在计算一个key在table中的位置时,用的是table的长度减1,与hash值取位与的结果。而不是取余(%)操作。

如果一个table的长度为8,那么n=8 (1000),n-1=7 (111),如果hash是什么值,取and的结果一定是000 ~ 111 之间,即0-7,正好对应table的index的范围。

注释中写道,Because the table uses power-of-two masking, sets of hashes that vary only in bits above the current mask will always collide.

翻译过来就是:table的长度总是2的n次幂,如果一组hash值只是在(111....1111)之上的高位互相不同,那么它们与(n-1) 位与 的结果总会碰撞。

一句话概括就是,key只有与(n-1)低位为1的长度相同位参与了hash碰撞的计算,高位没有体现出来。

JDK作者的解决方案是:(h = key.hashCode()) ^ (h >>> 16), JDK的doc中一开始说: spread higher bits of hash to lower

将高位的影响传播到低位,这样与(n-1)位与的计算,高低位就同时参与了。

我们都知道,一个int值是32位的,hash >>> 16 的含义就是右移16位,左边以0补齐。移位的结果是,低16位被抛弃,原高16位变成新低16位,新高16位用0补充。

0与0异或是0,0与1异或是1,即一个bit与0异或结果不变。 所以,hash xor (hash >>> 16) 的最终结果是:高16位不变,低16位与高16位异或。

如果 (n-1) 的二进制表示有16位,那么 n = 2的16次方 =  65536,hashmap的容量只要不大于65536,都是高低混合之16位在参与碰撞检测。

hashmap的hash方法源doc解读的更多相关文章

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

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

  2. HashMap之Hash碰撞源码解析

    转自:https://blog.csdn.net/luo_da/article/details/77507315 https://www.cnblogs.com/tongxuping/p/827619 ...

  3. AbstractCollection类中的 T[] toArray(T[] a)方法源码解读

    一.源码解读 @SuppressWarnings("unchecked") public <T> T[] toArray(T[] a) { //size为集合的大小 i ...

  4. hashmap的put方法源码分析

    put主源码如下: public V put(K key, V value) { if (key == null) return putForNullKey(value); int hash = ha ...

  5. hashMap 源码解读理解实现原理和hash冲突

    hashMap 怎么说呢. 我的理解是 外表是一个set 数组,无序不重复 . 每个set元素是一个bean ,存着一对key value 看看代码吧 package test; import jav ...

  6. 关于HashMap中hash()函数的思考

    关于HashMap中hash()函数的思考 JDK7中hash函数的实现   static int hash(int h) { h ^= (h >>> 20) ^ (h >&g ...

  7. HashMap的hash分析

    哈希 Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入,通过散列算法,变换成固定长度的输出,该输出就是散列值.这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空 ...

  8. JDK1.8中HashMap的hash算法和寻址算法

    JDK 1.8 中 HashMap 的 hash 算法和寻址算法 HashMap 源码 hash() 方法 static final int hash(Object key) { int h; ret ...

  9. jdk1.8.0_45源码解读——HashMap的实现

    jdk1.8.0_45源码解读——HashMap的实现 一.HashMap概述 HashMap是基于哈希表的Map接口实现的,此实现提供所有可选的映射操作.存储的是<key,value>对 ...

随机推荐

  1. tab切换效果 网站中的图片自动切换

    网站中的图片自动切换 今天上一套tab切换效果的代码 动图就自己实现吧! 下面贴HTML代码,大体分两部分,图片div和按钮div,代码很容易看懂~ <!DOCTYPE html> < ...

  2. 爬虫 selenium + phantomjs / chrome

    selenium 模块 Web自动化测试工具, 可运行在浏览器,根据指定命令操作浏览器, 必须与第三方浏览器结合使用 安装 sudo pip3 install selenium phantomjs 浏 ...

  3. JMeter4.0以上 分布式测试报错 "server failed start Listen failed on port"

    使用JMeter4.0做分布式测试的是否,我的电脑作为肉鸡(执行机),双击jmeter-server.bat后显示失败 Found ApacheJMeter_core.jarUsing local p ...

  4. spring boot 启动报 java.lang.NoClassDefFoundError: ch/qos/logback/core/spi/LifeCycle 错误

    Failed to instantiate SLF4J LoggerFactory Reported exception: java.lang.NoClassDefFoundError: ch/qos ...

  5. 【转】jstat命令查看jvm的GC情况 (以Linux为例)

    [From]https://www.cnblogs.com/yjd_hycf_space/p/7755633.html jstat命令可以查看堆内存各部分的使用量,以及加载类的数量.命令的格式如下: ...

  6. Python核心编程练习题

    1.输入一个数值,判断是否为正数,负数,小数,以及字符串 import re def is_number(num): pattern = re.compile(r'^[-+]?[-0-9]\d*\.\ ...

  7. spring-boot集成2:集成lombok

    Why lombok? lombok可以帮我们从实体类的getter.setter.constructor和toString等样板代码中解脱出来,使用lombok可以开发出更优雅的代码 1.maven ...

  8. Beego框架的一条神秘日志引发的思考

    公司目前的后台是用Beego框架搭的,并且为了服务的不中断升级,我们开启了Beego的Grace模块,用于热升级支持.一切都跑井然有序,直到有一天,领导甩出一些服务日志,告知程序一直报错: 2018/ ...

  9. centos 6.5安装erlang和RabbitMQ

    一.安装erlang 1.下载erlang源码 git clone https://github.com/erlang/otp.git 2.编译并安装erlang cd otp ./otp_build ...

  10. 应用安全 - 工具 | 平台 - gitlist - 漏洞 - 汇总

    简介 用途 Github仓库查看器 CVE-2014-4511 Date 类型 远程代码执行 影响范围 gitlist 0.4.0及之前版本