我们都知道,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之扰动函数和低位掩码的更多相关文章

  1. 关于 HashMap 随笔

    hashMap 的一些认识: 基于哈希表的Map接口的非同步实现,定义了键映射到值的规则 此实现提供所有可选的映射操作,并允许使用null值和null键 根据hash算法,确定key-value的存贮 ...

  2. HashMap是如何工作的

    目录 1 HashMap在JAVA中的怎么工作的? 2 什么是哈希? 3 HashMap 中的 Node 类 4 键值对在 HashMap 中是如何存储的 5 哈希碰撞及其处理 6 HashMap 的 ...

  3. HashMap中的hash函数

    在写一个HashSet时候有个需求,是判断HashSet中是否已经存在对象,存在则取出,不存在则add添加.HashSet也是通过HashMap实现,只用了HashMap的key,value都存储一个 ...

  4. 学习HashMap的笔记

    对于HashMap只是学习了下put,remove方法,hashMap是数组+链表+红黑树组成 所以下面贴出我自己给代码的注释,看不懂的见谅哈,毕竟我也是刚了解,如果有错误的地方请指出,非常感谢 pu ...

  5. 2、JDK8中的HashMap实现原理及源码分析

    本篇提纲.png 本篇所述源码基于JDK1.8.0_121 在写上一篇线性表的文章的时候,笔者看的是Android源码中support24中的Java代码,当时发现这个ArrayList和Linked ...

  6. 【JDK1.8】Java HashMap实现细节

    底层是用数组实现的 /** * The table, initialized on first use, and resized as * necessary. When allocated, len ...

  7. Java源码系列2——HashMap

    HashMap 的源码很多也很复杂,本文只是摘取简单常用的部分代码进行分析.能力有限,欢迎指正. HASH 值的计算 前置知识--位运算 按位异或操作符^:1^1=0, 0^0=0, 1^0=0, 值 ...

  8. JDK8中的HashMap实现原理及源码分析

    大纲 一.什么是Hash?什么是HashMap? 二.HashMap的内部实现机制 1.HashMap基本元素 ①DEFAULT_INITIAL_CAPACITY&MAXIMUM_CAPACI ...

  9. Java容器:HashMap连环炮

    本文来源于:https://mp.weixin.qq.com/s/oRx-8XXbgage9Hf97WrDQQ, 公众号:安琪拉的博客 前言 HashMap应该算是Java后端工程师面试的必问题,因为 ...

随机推荐

  1. Untiy3D学习笔记记录

    一,原点和中心点 pivot(原点):位置移动的点(模型的原点不会发生变化) center(中心点):计算模型的中心,会发现变化(比如有两个cube,他的中心点会计算在两个模型的中间) 二,prefa ...

  2. win32 socket编程(四)——服务器端实例(TCP)

    //Server服务器端Server.cpp 1 // 定义控制台应用程序的入口点. // #include "stdafx.h" #include <winsock2.h& ...

  3. 1、控制器运行一个Process进程,等待不等待的问题

    一.区别 public static async void Execute(string para, string ffmpegPath, string timestr, string Id, str ...

  4. TensorFlow 安装及使用

    安装 (1)安装包安装:pip install tensorflow==1.14 -i https://pypi.douban.com/simple virtualenv -p /usr/bin/py ...

  5. mysql查询每个部门/班级前几名

    Employee 表包含所有员工信息,每个员工有其对应的 Id, salary 和 department Id . +----+-------+--------+--------------+ | I ...

  6. oralce 汇编02

    Assembler Directives .align integer, padThe .align directive causes the next data generated to be al ...

  7. onupdate

    数据的初始化显示刚开始写在onupdate中,文档类中的数据更新之后,希望通过调用UpdateAllViews(FALSE)来实现视图的更新,可以实现!后来觉得不妥,想把初始化显示写在ondraw中, ...

  8. canvas toBlob ,ie兼容

    /* canvas-toBlob.js * A canvas.toBlob() implementation. * 2016-05-26 * * By Eli Grey, http://eligrey ...

  9. SoupUI 结合loadrunner压力测试

    SoupUI 结合loadrunner压力测试 上一篇介绍了SoupUI接口测试,因为工作需要,需要在loadrunner进行websocket的压力测试,当然,SoupUI本身也是可以做性能测试的 ...

  10. @ControllerAdvice全局数据预处理

    在传统项目的Controller的方法中传入参数,对象中的属性相同时,会出现以下错误         Book类和Author类     这是因为两个对象中的name相同,传参时分不清西游记和六小龄童 ...