hashmap的hash方法源doc解读
/**
* 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解读的更多相关文章
- Java中hashCode()方法以及HashMap()中hash()方法
Java的Object类中有一个hashCode()方法: public final native Class<?> getClass(); public native int hashC ...
- HashMap之Hash碰撞源码解析
转自:https://blog.csdn.net/luo_da/article/details/77507315 https://www.cnblogs.com/tongxuping/p/827619 ...
- AbstractCollection类中的 T[] toArray(T[] a)方法源码解读
一.源码解读 @SuppressWarnings("unchecked") public <T> T[] toArray(T[] a) { //size为集合的大小 i ...
- hashmap的put方法源码分析
put主源码如下: public V put(K key, V value) { if (key == null) return putForNullKey(value); int hash = ha ...
- hashMap 源码解读理解实现原理和hash冲突
hashMap 怎么说呢. 我的理解是 外表是一个set 数组,无序不重复 . 每个set元素是一个bean ,存着一对key value 看看代码吧 package test; import jav ...
- 关于HashMap中hash()函数的思考
关于HashMap中hash()函数的思考 JDK7中hash函数的实现 static int hash(int h) { h ^= (h >>> 20) ^ (h >&g ...
- HashMap的hash分析
哈希 Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入,通过散列算法,变换成固定长度的输出,该输出就是散列值.这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空 ...
- JDK1.8中HashMap的hash算法和寻址算法
JDK 1.8 中 HashMap 的 hash 算法和寻址算法 HashMap 源码 hash() 方法 static final int hash(Object key) { int h; ret ...
- jdk1.8.0_45源码解读——HashMap的实现
jdk1.8.0_45源码解读——HashMap的实现 一.HashMap概述 HashMap是基于哈希表的Map接口实现的,此实现提供所有可选的映射操作.存储的是<key,value>对 ...
随机推荐
- android下载网络图片,设置宽高,等比缩放
使用Picasso组件去下载图片会发现图片宽高会变形不受等比缩放控制,即使设置了图片的 scaleType,可能是对Picasso的api没有用对, Picasso.with(this.activit ...
- 非监督的降维算法--PCA
PCA是一种非监督学习算法,它能够在保留大多数有用信息的情况下,有效降低数据纬度. 它主要应用在以下三个方面: 1. 提升算法速度 2. 压缩数据,减小内存.硬盘空间的消耗 3. 图示化数据,将高纬数 ...
- tensorflow二进制文件读取与tfrecords文件读取
1.知识点 """ TFRecords介绍: TFRecords是Tensorflow设计的一种内置文件格式,是一种二进制文件,它能更好的利用内存, 更方便复制和移动,为 ...
- JAVA多线程程序ProgressBar
JAVA多线程程序ProgressBar 题目简介: 思维导图: 实验代码:建议先看CalThread类,计算线程的实现,再作基本CalFrame类的界面, 然后作ReadThread类,结合CalF ...
- httpClient模仿Basic Auth
httpclient代码调用如下: @GetMapping("loginTest") public String httpClientWithBasicAuth() { Strin ...
- Kibana 创建索引 POST 403 (forbidden) on create index
一.问题描述: Kibana创建索引:kibana > management > index patterns > create index pattern 索引名称: mercha ...
- EncryptFac 加解密小工具
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- python-Web-django-图形验证
import random def get_random_color(): return (random.randint(0, 255), random.randint(0, 255), random ...
- DirectX* 11 多线程渲染的性能、方法和实践
对于在 CPU 上运行的 PC 游戏,渲染通常是主要的性能瓶颈:多线程渲染是一种消除瓶颈的有效方法.本文研究了 DirectX* 11 多线程渲染的性能可扩展性,讨论了多线程渲染的两种基本方法,并介绍 ...
- Linux 使用中history 默认记录数不够用了?
1.默认情况下,系统能保存1000条的历史命令. #echo $HISTSIZE 2.那么1000条不够用,该怎么办呢? #vi /etc/profile 修改HISTSIZE=1000 > ...