我们都知道,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. Azkaban和Oozie的区别

    Azkaban和Oozie的区别: 当前,实际生产中最流行的两种Hadoop工作流引擎是Azkaban与Oozie.但活跃度最高的当是Azkaban了,下面对两者的异同之处作如下对比. 功能对比 Az ...

  2. 箭头函数的this指向问题

    this指向的固定化,并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this.正是因为它没有this,所以也就不能用作构造函数 ...

  3. 2018-12-25-win10-uwp-显示SVG

    title author date CreateTime categories win10 uwp 显示SVG lindexi 2018-12-25 10:37:5 +0800 2018-2-13 1 ...

  4. linux 验证 NFS 是否成功

    服务器端----->>客户端 1. 服务器端 [root@allentuns ~]# ifconfig |grep "Bcast" inet addr:192.168. ...

  5. tenorflow 模型调优

    # Create the Timeline object, and write it to a json from tensorflow.python.client import timeline t ...

  6. 为什么需要bootloader

    本文链接:https://blog.csdn.net/u012351051/article/details/50557899 受单片机和ARM7等小型CPU设备编程思维的影响,开始对嵌入式linux和 ...

  7. thinkphp 视图view

    一. 继承Controller类 <?php namespace app\index\controller; use http\Params; use think\Config; use thi ...

  8. pytorch 指定GPU训练

    # 1: torch.cuda.set_device(1) # 2: device = torch.device("cuda:1") # 3:(官方推荐)import os os. ...

  9. CentOS 6.3下Zabbix监控MySQL数据库参数

    系统环境:CentOS 6.3 x64  http://www.linuxidc.com/Linux/2012-12/76583.htm mysql:    mysql-5.6.10 http://w ...

  10. django 多条数据显示的坑(怪自己)

    今天的问题是,一个接口执行了很多次,每次都会在结果表里面记录一条结果信息,在查看接口详情页面,我想只展示一条,然后就进入误区了 第一个是怪自己手残,api_id  被自己写成app_id了 第二个是筛 ...