HashMap之扰动函数和低位掩码
我们都知道,hashMap在实现的时候,为了寻找在数组上的位置,主要做了两件事
int hash = hash(key);
int i = indexFor(key, table.length);
这个时候得到i才是数组上的位置。
这两个方法详解如下
JDK8对扰动函数的修改,只进行了一次移位(又移16bit),再和key.hashCode()做异或,如图
static final int hash(Object key){
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
这个散列值是不能直接拿来用的。用之前还要先做对数组的长度取模运算,得到的余数才能用来访问数组下标。源码中模运算是在这个indexFor( )函数里完成的。
bucketIndex = indexFor(int h, table.length);
其中IndexFor代码
static int indexFor(int h, int length){
return h & (length - 1);
}
indexFor代码,正好解释了为什么HashMap的数组长度要取2的整次幂。因为这样(数组长度-1)正好相当于一个“低位掩码”。“与”操作的结果就是散列值的高位全部归零,只保留低位值,用来做数组下标访问。以初始长度16为例,16-1=15。2进制表示是00000000 00000000 00001111。和某散列值做“与”操作如下,结果就是截取了最低的四位值。

但这时候问题就来了,这样就算我的散列值分布再松散,要是只取最后几位的话,碰撞也会很严重。更要命的是如果散列本身做得不好,分布上成等差数列的漏洞,恰好使最后几个低位呈现规律性重复,就无比蛋疼。
这时候“扰动函数”的价值就体现出来了,说到这里大家应该猜出来了。看下面这个图,

右位移16位,正好是32bit的一半,自己的高半区和低半区做异或,就是为了混合原始哈希码的高位和低位,以此来加大低位的随机性。而且混合后的低位掺杂了高位的部分特征,这样高位的信息也被变相保留下来。
JDK 7做了4次右移,估计是边际效应的原因,JDK8就只做了一次右移。
另外 JDK8在链表长度超过8的时候,就使用红黑树做存储。这一改变大大优化了很多性能。
HashMap之扰动函数和低位掩码的更多相关文章
- 关于 HashMap 随笔
hashMap 的一些认识: 基于哈希表的Map接口的非同步实现,定义了键映射到值的规则 此实现提供所有可选的映射操作,并允许使用null值和null键 根据hash算法,确定key-value的存贮 ...
- HashMap是如何工作的
目录 1 HashMap在JAVA中的怎么工作的? 2 什么是哈希? 3 HashMap 中的 Node 类 4 键值对在 HashMap 中是如何存储的 5 哈希碰撞及其处理 6 HashMap 的 ...
- HashMap中的hash函数
在写一个HashSet时候有个需求,是判断HashSet中是否已经存在对象,存在则取出,不存在则add添加.HashSet也是通过HashMap实现,只用了HashMap的key,value都存储一个 ...
- 学习HashMap的笔记
对于HashMap只是学习了下put,remove方法,hashMap是数组+链表+红黑树组成 所以下面贴出我自己给代码的注释,看不懂的见谅哈,毕竟我也是刚了解,如果有错误的地方请指出,非常感谢 pu ...
- 2、JDK8中的HashMap实现原理及源码分析
本篇提纲.png 本篇所述源码基于JDK1.8.0_121 在写上一篇线性表的文章的时候,笔者看的是Android源码中support24中的Java代码,当时发现这个ArrayList和Linked ...
- 【JDK1.8】Java HashMap实现细节
底层是用数组实现的 /** * The table, initialized on first use, and resized as * necessary. When allocated, len ...
- Java源码系列2——HashMap
HashMap 的源码很多也很复杂,本文只是摘取简单常用的部分代码进行分析.能力有限,欢迎指正. HASH 值的计算 前置知识--位运算 按位异或操作符^:1^1=0, 0^0=0, 1^0=0, 值 ...
- JDK8中的HashMap实现原理及源码分析
大纲 一.什么是Hash?什么是HashMap? 二.HashMap的内部实现机制 1.HashMap基本元素 ①DEFAULT_INITIAL_CAPACITY&MAXIMUM_CAPACI ...
- Java容器:HashMap连环炮
本文来源于:https://mp.weixin.qq.com/s/oRx-8XXbgage9Hf97WrDQQ, 公众号:安琪拉的博客 前言 HashMap应该算是Java后端工程师面试的必问题,因为 ...
随机推荐
- git submodule删除多余模块
rm -rf 子模块目录 删除子模块目录及源码 vi .gitmodules 删除项目目录下.gitmodules文件中子模块相关条目 vi .git/config 删除配置项中子模块相关条目 rm ...
- 线程局部变量ThreadLocal实现原理
ThreadLocal,即线程局部变量,用来为每一个使用它的线程维护一个独立的变量副本.这种变量只在线程的生命周期内有效.并且与锁机制那种以时间换取空间的做法不同,ThreadLocal没有任何锁机制 ...
- 【vue】父子组件间通信----传函数
(一)子组件 调用 父组件 方法 方式一) 子组件中通过this.$parent.event来调用父组件的方法 父组件 <template> <div> <child&g ...
- springboot+UEditor图片上传
springboot+UEDitor百度编辑器整合图片上记录于此 1.下载ueditor插件包,解压到static/ueditor目录下 2.在你所需实现编辑器的页面引用三个JS文件 1) uedi ...
- 定位公众号页面,跳转之后 vuejs 失效问题
是第一个页面的. data () { }, 写成了这样,没写返回 {} 5555~. 网页中死活可以,微信中死活不行. data () { return {} },
- html 头部设置
https://juejin.im/post/5a4ae29b6fb9a04504083cac <head> <meta charset="UTF-8"> ...
- Kettle连接MySQL错误:OPTION SQL_SELECT_LIMIT=DEFAULT
由于升级了MySQL到5.6,运行ETL报错: OPTION SQL_SELECT_LIMIT=DEFAULT 上网查询原来是MySQL的驱动版本不一致,之前的驱动不支持这样的写法,于是上网下载对应的 ...
- python每日练习0801
#有一堆100块的石头,2个人轮流随机从中取1-5块,谁取最后一块就谁win,编程实现 import random stones = 100 count = 0 while stones > 0 ...
- python 全栈开发,Day53(jQuery的介绍,jQuery的选择器,jQuery动画效果)
01-jQuery的介绍 1.为什么要使用jQuery 在用js写代码时,会遇到一些问题: window.onload 事件有事件覆盖的问题,因此只能写一个事件. 代码容错性差. 浏览器兼容性问题. ...
- php strripos()函数 语法
php strripos()函数 语法 作用:寻找某字符串中某字符最后出现的位置,不区分大小写.大理石平台 语法:strripos(string,find,start) 参数: 参数 描述 strin ...