我们都知道,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. JVM Heap Memory和Native Memory

    JVM管理的内存可以总体划分为两部分:Heap Memory和Native Memory.前者我们比较熟悉,是供Java应用程序使用的:后者也称为C-Heap,是供JVM自身进程使用的.Heap Me ...

  2. Rsync安装部署

    Rsync安装部署 1.Rsync  简介 Rsync  是一款开源的.快速的 多功能的 可以实现全量以及增量的本地或者是远程的数据同步备份的优秀工具,并且可以不进行改变原有的数据属性信息,实现数据的 ...

  3. python3-sorted

    排序也是在程序中经常用到的算法.无论使用冒泡排序还是快速排序,排序的核心是比较两个元素的大小.如果是数字,我们可以直接比较,但如果是字符串或者两个dict呢?直接比较数学上的大小是没有意义的,因此,比 ...

  4. MongoDB Compass管理工具下载、安装和使用

    内容来自:https://jingyan.baidu.com/article/925f8cb884f6f8c0dce0565a.html ,https://blog.csdn.net/bg101775 ...

  5. vue开发可复用组件

    组件,是一个具有一定功能,且不同组件间功能相对独立的模块.高内聚.低耦合.   开发可复用性的组件应遵循以下原则:   1.规范化命名:组件的命名应该跟业务无关,而是依据组件的功能命名. 2.数据扁平 ...

  6. spring mvc 和spring boot 中注解的使用

    1 spring mvc和spring boot之间的关系 spring boot包含spring mvc.所以,spring mvc的注解在spring boot总都是可以用的吗? spring b ...

  7. Selenium-WebDriverApi介绍

    浏览器操作: #刷新 driver.refresh() from selenium import webdriver driver=webdriver.Chrome() driver.get('htt ...

  8. Cocoapods组件化之搭建组件化项目框架

    一,概述 随着公司业务需求的不断迭代发展,工程的代码量和业务逻辑也越来越多,原始的开发模式和架构已经无法满足我们的业务发展速度了,这时我们就需要将原始项目进行一次重构大手术了.这时我们应该很清晰这次手 ...

  9. spring mvc中的@Entity是什么意思?

    @Entitypublic Class JavaBean{}标注该类为实体类.

  10. 穿戴-智能穿戴-ProjectGlass:谷歌眼镜(Google Project Glass)

    ylbtech-穿戴-智能穿戴-ProjectGlass:谷歌眼镜(Google Project Glass) 谷歌眼镜(Google Project Glass)是由谷歌公司于2012年4月发布的一 ...