java hashmap hash算法,jdk1.8 中 HashMap 的 hash 算法和数组寻址
开篇
本文基于 jdk1.8 讲述 HashMap 的 hash 算法,但是不会详细介绍其他相关内容(比如用法,底层数据结构)。所以必须事先知晓下面几点:
HashMap 的底层数据结构是数组,在数组的基础上再去考虑链表或者红黑树
put 一个 key-value 时,会先计算出在数组中的索引位置,再考虑剩下的步骤
位运算操作(异或,与)
java 运算符优先级
正文
HashMap 是基于 key-value 形式存放元素的,所使用的方法是 put(key, value)。
1. HashMap 的 put 方法源码
// 再次强调这是 jdk1.8 源码
public V put(K key, V value) {
// 这里调用 putVal() 方法
// 传入的第一个参数:是根据 key 计算出的 hash 值
return putVal(hash(key), key, value, false, true);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
Node[] tab; Node p; int n, i;
// 获取数组的长度
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
// 计算元素在数组中的索引位置
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
// 忽略部分代码
}
}
2. 从上面的源码中提取出两个代码片段
2.1 片段 1 - 计算 hash 值
static final int hash(Object key) {
int h;
return (key == null) ?
0 :
(h = key.hashCode()) ^ (h >>> 16);
}
如果 key 为 null,hash == 0
否则
先取出 key 的 hashCode 值,得到 h1
然后对 h1 右移 16 位,得到 h2
最后将 h1 和 h2 进行异或运算,得到最终的 hash 值
举个例子吧:
先获得 key 的 hashCode 值,得到 h1
1111 1111 1111 1111 1010 1010 1010 1010
对 h1 右移 16 位,得到 h2
0000 0000 0000 0000 1111 1111 1111 1111
最后将 h1 和 h2 进行异或运算
1111 111 1111 1111 0101 0101 0101 0101
图解 1
图解 2
结论如下:
1. 最终结果就是将 h1 的高 16 位 和低 16位进行了异或运算。
2. 达到的效果就是混合原始哈希码的高位和低位,以此来加大低位的随机性。
3. 顺带着,低 16 位可以同时拥有高 16 位的信息。
2.2 片段 2 - 计算元素在数组中的索引位置
i = (n - 1) & hash
如果让我们来做,通常会想到用下面取模的方式计算索引。
i = hash % n
其实,上面两种算法得到的结果是一样的(自行验证),就当这是一个数学公式吧。
【前提是 HashMap 的数组长度要取2的整次幂,这也说明了为什么 HashMap 的初始容量不能随便给】
但是两者相比而言,位运算的效率会更高,所以 HashMap 用了第一种算法。
总结
当 HashMap 的数组长度是 2 的整次幂时,(n - 1) & hash与 hash % n计算的结果是等价的,而后者是更容易想到的办法,前者是更有效率的办法。
HashMap 的 hash 算法(看起来分了好几步),其实就是把 hashCode 值的高 16 位 与 低 16 位进行了异或运算,目的就是增大随机性。
java hashmap hash算法,jdk1.8 中 HashMap 的 hash 算法和数组寻址相关推荐
- jdk1.8中HashMap扰动函数及数组长度为什么是2的n次方介绍
文章目录 前言 一.什么是二进制? 二.计算机采用二进制的原因 三.十进制与二进制相互转换 十进制转成二进制 二进制转换为十进制 与.或.异或运算 按位异或 按位与运算 按位或运算 Jdk1.8中Ha ...
- [Java]JDK1.7中HashMap的并发死链
[Java]JDK1.7中HashMap的并发死链 HashMap的并发死链现象发生在扩容时,在扩容过程中**transfer()**方法负责把旧的键值对转移到新的表中,其代码如下: void tra ...
- JDK1.7和JDK1.8中HashMap是线程不安全的,并发容器ConcurrentHashMap模型
一.HashMap是线程不安全的 前言 只要是对于集合有一定了解的一定都知道HashMap是线程不安全的,我们应该使用ConcurrentHashMap.但是为什么HashMap是线程不安全的呢,之前 ...
- 七、JDK1.7中HashMap扩容机制
导读 前面文章一.深入理解-Java集合初篇 中我们对Java的集合体系进行一个简单的分析介绍,上两篇文章二.Jdk1.7和1.8中HashMap数据结构及源码分析 .三.JDK1.7和1.8Hash ...
- JDK1.7中HashMap底层实现原理
JDK1.7中HashMap底层实现原理 一.数据结构 HashMap中的数据结构是数组+单链表的组合,以键值对(key-value)的形式存储元素的,通过put()和get()方法储存和获取对象. ...
- Day1、为什么JDK1.8中HashMap从头插入改成尾插入
目录 Day1.为什么JDK1.8中HashMap从头插入改成尾插入 存储方式 静态常量 插入元素 扩容 拓展问题 1.为什么JDK1.8采用红黑树存储Hash冲突的元素? 2.为什么在长度小于8时使 ...
- 八、JDK1.8中HashMap扩容机制
导读 前面文章一.深入理解-Java集合初篇 中我们对Java的集合体系进行一个简单的分析介绍,上两篇文章二.Jdk1.7和1.8中HashMap数据结构及源码分析 .三.JDK1.7和1.8Hash ...
- 详述 JDK1.7 中 HashMap 会发生死链的原因
文章目录 前置知识 死循环执行步骤1 死循环执行步骤2 死循环执行步骤3 解决方案 总结 前置知识 HashMap死循环是一个比较常见.比较经典的问题,在日常的面试中出现的频率比较高,所以接下来咱们通 ...
- 【死链】JDK1.7中HashMap在多线程环境的并发问题源码分析
文章目录 一.HashMap在JDK1.7中的并发问题 二.死链如何产生? 三.如何解决HashMap并发问题 参考文献 一.HashMap在JDK1.7中的并发问题 在JDK1.7中的HashMap ...
最新文章
- 将某表一行数据的某些字段插入到该表
- Android 使用jtds远程访问数据库
- json文件读取之reader.onload中的定义的变量在其函数外部进行处理
- mysql数据库 day05
- Tcpdump抓包实操
- 为什么不敢和别人竞争_孩子在学校不敢竞争?你该怎么做
- Android----- MD5加密(登录注册得到与IOS相同的加密值,并且解决两个平台汉字加密不相同问题)...
- 数据接口复习 3 stack and queue
- 外卖类应用的竞争与趋势
- Latex 中文使用方法和示例——分别基于MiKTeX(CTeX套装)、TeXLive 编译系统测试CJK、ctex 宏包,PDFLaTeX、XeLaTeX编译命令及GBK、UTF-8文件编码的使用
- 微信小程序云开发之云数据库查询及动态输入
- 身份证号码验证(直接调用idCardValidate(String idCard) )
- Niagara模块微信公众号连接
- 2023 年的 Web Worker 项目实践
- 学习计算机嵌入式的笔记汇总
- 如何使用ttf字体文件
- (附源码)springboot福佳生活超市进销存管理系统 毕业设计261620
- 【面试题】网易互娱(游戏)2020校招在线笔试-游戏研发第一批[水平线]
- 提高独立站转化率的小技巧
- 机房计算机怎么查找192文档,计算机专业机房简介
热门文章
- 零基础入门天池NLP赛事之——新闻文本分类(5)
- 异质性分析:系数平滑可变模型
- 关于Latex中生僻字显示问题
- 摄像头8mm可以看多远_折叠屏、透明屏、卷曲屏、拼接屏、屏下摄像头...未来屏显的先机都在这里...
- 解决 iPhone X 屏幕底部空白问题
- 选择大于努力,错失字节跳动数亿身价,含泪分享
- [MICCAI2019]Multi-view Learning with Feature Level Fusion for Cervical Dysplasia Diagnosis
- mysql 怎么打开dmp_mySQL 中怎么将dmp文件导入数据库
- 互联网银行分化:头部优势凸显,尾部承压明显
- 《人工智能》之语音识别概述