【JDK1.8】Java HashMap实现细节
底层是用数组实现的
/**
* The table, initialized on first use, and resized as
* necessary. When allocated, length is always a power of two.
* (We also tolerate length zero in some operations to allow
* bootstrapping mechanics that are currently not needed.)
*/
transient Node<K,V>[] table;
主要介绍一下Java 8源码中的HashMap中的hash原理,先看代码
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
Java 7中是这样的
static int hash(int h) {
// This function ensures that hashCodes that differ only by
// constant multiples at each bit position have a bounded
// number of collisions (approximately 8 at default load factor). h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
上面这段代码其实叫做"扰动函数"
下面摘自https://www.zhihu.com/question/20733617
大家都知道上面代码里的key.hashCode()函数调用的是key键值类型自带的哈希函数,返回int型散列值。
理论上散列值是一个int型,如果直接拿散列值作为下标访问HashMap主数组的话,考虑到2进制32位带符号的int表值范围从-2147483648到2147483648。前后加起来大概40亿的映射空间。只要哈希函数映射得比较均匀松散,一般应用是很难出现碰撞的。
但问题是一个40亿长度的数组,内存是放不下的。你想,HashMap扩容之前的数组初始大小才16。所以这个散列值是不能直接拿来用的。用之前还要先做对数组的长度取模运算,得到的余数才能用来访问数组下标。源码中模运算是在这个indexFor( )函数里完成的。
bucketIndex = indexFor(hash, table.length);
indexFor的代码也很简单,就是把散列值和数组长度做一个"与"操作,
static int indexFor(int h, int length) {
return h & (length-1);
}
顺便说一下,这也正好解释了为什么HashMap的数组长度要取2的整次幂。因为这样(数组长度-1)正好相当于一个“低位掩码”。“与”操作的结果就是散列值的高位全部归零,只保留低位值,用来做数组下标访问。以初始长度16为例,16-1=15。2进制表示是00000000 00000000 00001111。和某散列值做“与”操作如下,结果就是截取了最低的四位值。
10100101 11000100 00100101
& 00000000 00000000 00001111
----------------------------------
00000000 00000000 00000101 //高位全部归零,只保留末四位
但这时候问题就来了,这样就算我的散列值分布再松散,要是只取最后几位的话,碰撞也会很严重。更要命的是如果散列本身做得不好,分布上成等差数列的漏洞,恰好使最后几个低位呈现规律性重复,就无比蛋疼。
这时候“扰动函数”的价值就体现出来了,说到这里大家应该猜出来了。看下面这个图,
右位移16位,正好是32bit的一半,自己的高半区和低半区做异或,就是为了混合原始哈希码的高位和低位,以此来加大低位的随机性。而且混合后的低位掺杂了高位的部分特征,这样高位的信息也被变相保留下来。
最后我们来看一下Peter Lawley的一篇专栏文章《An introduction to optimising a hashing strategy》里的的一个实验:他随机选取了352个字符串,在他们散列值完全没有冲突的前提下,对它们做低位掩码,取数组下标。
结果显示,当HashMap数组长度为512的时候,也就是用掩码取低9位的时候,在没有扰动函数的情况下,发生了103次碰撞,接近30%。而在使用了扰动函数之后只有92次碰撞。碰撞减少了将近10%。看来扰动函数确实还是有功效的。
但明显Java 8觉得扰动做一次就够了,做4次的话,多了可能边际效用也不大,所谓为了效率考虑就改成一次了。
【JDK1.8】Java HashMap实现细节的更多相关文章
- JDK1.7中HashMap底层实现原理
一.数据结构 HashMap中的数据结构是数组+单链表的组合,以键值对(key-value)的形式存储元素的,通过put()和get()方法储存和获取对象. (方块表示Entry对象,横排表示数组ta ...
- 【转】Java HashMap的死循环
问题的症状 从前我们的Java代码因为一些原因使用了HashMap这个东西,但是当时的程序是单线程的,一切都没有问题.后来,我们的程序性能有问题,所以需要变成多线程的,于是,变成多线程后到了线上,发现 ...
- Java - HashMap 多线程安全解析
HashMap多线程并发问题分析 多线程put后可能导致get死循环 从前我们的Java代码因为一些原因使用了HashMap这个东西,但是当时的程序是单线程的,一切都没有问题.后来,我们的程序性能有问 ...
- Java总结——常见Java集合实现细节(1)
Java提高——常见Java集合实现细节(1) 2018年04月18日 15:07:35 阅读数:25 集合关系图 Set和Map set代表一种集合元素无序.集合元素不可重复的集合 map代表一种由 ...
- 十个问题带你了解和掌握java HashMap
十个问题带你了解和掌握java HashMap 一.前言 本篇内容是源于 " 由阿里巴巴Java开发规约HashMap条目引发的故事",并在此基础上加了自己的对HashMap更多的 ...
- java HashMap源码分析(JDK8)
这两天在复习JAVA的知识点,想更深层次的了解一下JAVA,所以就看了看JAVA的源码,把自己的分析写在这里,也当做是笔记吧,方便记忆.写的不对的地方也请大家多多指教. JDK1.6中HashMap采 ...
- Java:HashMap原理与设计缘由
前言 Java中使用最多的数据结构基本就是ArrayList和HashMap,HashMap的原理也常常出现在各种面试题中,本文就HashMap的设计与设计缘由作出一一讲解,并解答面试常见的一些问题. ...
- Java——HashMap底层源码分析
1.简介 HashMap 根据键的 hashCode 值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的. HashMap 最多只允许一条记录的key为 nu ...
- Java——HashMap集合详解
第一章 HashMap集合简介 1.1 介绍 HashMap基于哈希表的Map接口实现,是以key-value存储形式存在,即主要用来存放键值对.HashMap 的实现不是同步的,这意味着它不是线程安 ...
随机推荐
- 2018-2-13-win10-UWP-显示地图
title author date CreateTime categories win10 UWP 显示地图 lindexi 2018-2-13 17:23:3 +0800 2018-2-13 17: ...
- 服务器修改静态ip
ifconfig,看当前网卡名字 设置 ip地址,子网掩码 ,广播地址 ifconfig eth1 172.16.11.25 netmask 255.255.255.0 broadcast 172.1 ...
- Chocolatey Window系统下的软件管理工具
前言: 使用linux都喜欢使用yum ;apt-get来安装包,非常方便,那么windows也可以使用这样的方式. Chocolatey软件是Windows下的软件安装工具: 使用方法类似linux ...
- ida吧
经过IDA反编译后的代码是:int __cdecl Ompress(void *Dst, int a2, int a3, int a4)//dst( [esp+24h][ebp+4h] );a2([e ...
- eclipse里部署struts2
Struts2是一个比较出色的基于MVC设计模式的框架,是由Struts1和WebWork发展而来的,性能也比较稳定,现在是Apache软件基金会的一个项目,下面就来配置Struts2进行初始化的开发 ...
- tensorflow基础重新巩固
tensorflow框架整体结构 用张量tensor表示数据:计算图graph表示任务:在会话session中执行context: 通过变量维护状态:通过feed和fetch可以任意的操作(arbit ...
- 【leetcode】989. Add to Array-Form of Integer
题目如下: For a non-negative integer X, the array-form of X is an array of its digits in left to right o ...
- 【leetcode】976. Largest Perimeter Triangle
题目如下: Given an array A of positive lengths, return the largest perimeter of a triangle with non-zero ...
- TextView详解
android:autoLink设置是否当文本为URL链接/email/电话号码/map时,文本显示为可点击的链接.可选值(none/web /email/phone/map/all)android: ...
- 2019ccpc秦皇岛/Gym102361 I - Invoker dp
题意: 连续3个特定的按键(在这3个中不要求顺序)能使出某个技能,使出不同技能所需要的按键可以重叠,给你一个技能序列,问你最少花费多少次按键能按顺序使出这些招数. 题解: dp,dp[i][j]代表使 ...