Java8 HashMap扩容时为什么不需要重新hash
技巧: 与&操作 和 与 n 如8 与,为0 则位置不变
https://blog.csdn.net/zlp1992/article/details/104376309
java8在实现HashMap时做了一系列的优化,其中一个重要的优化即在扩容的时候,原有数组里的数据迁移到新数组里不需要重新hash,而是采用一种巧妙的方法,代码如下:
table = newTab;
if (oldTab != null) {
for (int j = 0; j < oldCap; ++j) {
Node<K,V> e;
if ((e = oldTab[j]) != null) {
oldTab[j] = null;
if (e.next == null)
newTab[e.hash & (newCap - 1)] = e;
else if (e instanceof TreeNode)
((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
else { // preserve order
Node<K,V> loHead = null, loTail = null;
Node<K,V> hiHead = null, hiTail = null;
Node<K,V> next;
do {
next = e.next;
if ((e.hash & oldCap) == 0) {
if (loTail == null)
loHead = e;
else
loTail.next = e;
loTail = e;
}
else {
if (hiTail == null)
hiHead = e;
else
hiTail.next = e;
hiTail = e;
}
} while ((e = next) != null);
if (loTail != null) {
loTail.next = null;
newTab[j] = loHead;
}
if (hiTail != null) {
hiTail.next = null;
newTab[j + oldCap] = hiHead;
}
}
}
}
}
return newTab;
}
可以看到它是通过将数据的hash与扩容前的长度进行与操作,根据结果为0还是不为0来做对应的处理e.hash & oldCap。
举个例子
比如数据 A它经过hash之后的值为 0111(二进制),一开始map中数组的长度是 8,根据定位的逻辑 (n-1)&hash,那么数据A的位置是:
(n-1)&hash = (8-1) & 0111 = 111 & 0111 = 0111
扩容之后数组长度是原来的2倍,即16,假设我们重新算一遍A的位置,那么应该是:
(n-1)&hash =(16-1) & 0111 = 1111 & 0111 = 0111
可以看到数据A扩容之后,如果重新计算hash的话,它的位置是没有发生变化的,来看一下 e.hash & oldCap的结果
e.hash & oldCap = 0111 & 8 = 0111 & 1000 = 0
比如数据B它经过hash之后的值为 1111,在扩容之前数组长度是8,数据B的位置是:
(n-1)&hash = (8-1) & 1111 = 111 & 1111 = 0111
扩容之后,数组长度是16,重新计算hash位置是:
(n-1)&hash = (16-1) & 1111 = 1111 & 1111 = 1111
可见数据B的位置发生了变化,同时新的位置和原来的位置关系是:
新的位置(1111)= 1000+原来的位置(0111)=原来的长度(8)+原来的位置(0111)
继续看一下e.hash & oldCap的结果
e.hash & oldCap = 1111 & 8 = 1111 & 1000 = 1000 (!=0)
那么有没有看出规律呢,因为每次扩容都是2的倍数,计算位置的时候是和数组的长度-1做与操作,那么影响位置的数据只有最高的一位,比如 8-1 =7= 0111 ,16-1=15=1111 ,对于每个数据来说只有从右边数第四位的值会影响结果,当数据的hash的右边第四位为1的时候位置会发生变化,如上面的数据B,如果第四位为0,那么数据不会发生变化,如上面的数据A,而这个第四位 1000 恰好又是扩容前的数组长度,因此可以根据e.hash & oldCap的结果来判断,如果是0,说明位置没有发生变化,如果不为0,说明位置发生了变化,而且新的位置=老的位置+老的数组长度。
不过为什么当某个bin只有一个数据的时候要重新hash呢?
if (e.next == null)
newTab[e.hash & (newCap - 1)] = e;
理论上也可以采用e.hash & oldCap这种方式?
Java8 HashMap扩容时为什么不需要重新hash的更多相关文章
- Java源码系列4——HashMap扩容时究竟对链表和红黑树做了什么?
我们知道 HashMap 的底层是由数组,链表,红黑树组成的,在 HashMap 做扩容操作时,除了把数组容量扩大为原来的两倍外,还会对所有元素重新计算 hash 值,因为长度扩大以后,hash值也随 ...
- jdk1.7中hashmap扩容时不会产生死循环
在扩容时 transfer( ) 方法中 newTable 新数组 局部变量 table 旧数组 全局变量 当第一个链表进行while循环时 执行到 e.next = newTable[i]; 时 n ...
- HashMap、Hashtable、HashSet三种hash集合的区别
转载:http://www.cnblogs.com/lzrabbit/p/3721067.html#h1 HashMap和Hashtable的区别 两者最主要的区别在于Hashtable是线程安全,而 ...
- Java8中HashMap扩容算法小计
Java8的HashMap扩容过程主要就是集中在resize()方法中 final Node<K,V>[] resize() { // ...省略不重要的 } 其中,当HashMap扩容完 ...
- JDK1.8 HashMap 扩容 对链表(长度小于默认的8)处理时重新定位的过程
关于HashMap的扩容过程,请参考源码或百度. 我想记录的是1.8 HashMap扩容是对链表中节点的Hash计算分析. 对术语先明确一下: hash计算指的确定节点在table[index]中的链 ...
- java 基础 --- java8 HashMap
问题 : HashMap 容量大小 (capacity)为什么为 2n HashMap 是线程安全的吗,为什么 HashMap 既然有hash进行排位还需要equals()作用是什么 文章部分图片 ...
- JAVA8 HashMap 源码阅读
序 阅读java源码可能是每一个java程序员的必修课,只有知其所以然,才能更好的使用java,写出更优美的程序,阅读java源码也为我们后面阅读java框架的源码打下了基础.阅读源代码其实就像再看一 ...
- Java8 HashMap详解
Java8 HashMap Java8 对 HashMap 进行了一些修改,最大的不同就是利用了红黑树,所以其由 数组+链表+红黑树 组成. 根据 Java7 HashMap 的介绍,我们知道,查找的 ...
- Java8 HashMap源码分析
java.util.HashMap是最常用的java容器类之一, 它是一个线程不安全的容器. 本文对JDK1.8.0中的HashMap实现源码进行分析. HashMap使用位运算巧妙的进行散列并使用链 ...
随机推荐
- mysql 去除前后空白字符
update table set field = replace(replace(replace(field,char(9),''),char(10),''),char(13),'');
- 【笔试必备】常见sql笔试题(30题)
sql是测试从业者必备的技能之一,基本上也是笔试必考内容. 所以,不要让sql拖了后腿,有些测友一遇到多表关联查询就犯晕,甚至连单表的执行顺序都没搞懂,下面简单介绍下,顺便给一些题供大家练习. 单表执 ...
- Java诊断神器:Arthas常用功能
最新原文:https://www.cnblogs.com/uncleyong/p/14944401.html Arthas是Alibaba开源的Java诊断工具,功能很强大,它是通过Agent方式来连 ...
- nmtui解决network-scripts目录下无网卡对应配置文件问题
1.问题出现的原因设备先安装了操作系统,后插上网卡到设备,就会出现/etc/sysconfig/network-scripts目录下无该网卡对应配置文件的问题,但是ifconfig命令能看见系统给该网 ...
- MySQL常用查询命令(连接查询&子查询)
多张表联合起来查询即为连接查询,可分为: 内连接:等值连接.非等值连接.自连接 外连接:右外连接.左外连接 也就是先把多张表通过某种指定条件用join...on...语法连接起来,然后再进行where ...
- SpreadJS + GcExcel 一出,谁与争锋!全栈表格技术轻松应对复杂公式计算场景(一)
设计思路篇 Excel是我们日常办公中最常用的电子表格程序,不仅可满足报表数据的计算需求,还可提供绘图.数据透视分析.BI和Visual Basic for Applications (VBA)宏语言 ...
- Shell脚本编写登陆小程序.sh
转至:https://www.cnblogs.com/gaohongyu/articles/12072594.html #!/bin/bash #Author:GaoHongYu #QQ:106176 ...
- html 多种空格转义字符
记录一下,空格的转义字符分为如下几种: 1. &160#;不断行的空白(1个字符宽度) 2. &8194#;半个空白(1个字符宽度) 3. &8195#;一个空白(2个 ...
- 教程10--hexo搭建
1.安装node.js 下载系统对应的node安装包一直下一步完成 2.安装git 参照git安装https://www.cnblogs.com/daxiang2008/p/10687616.html ...
- ImageNet2017文件介绍及使用
ImageNet2017文件介绍及使用 文件说明 imagenet_object_localization.tar.gz包含训练集和验证集的图像数据和地面实况,以及测试集的图像数据. 图像注释以PAS ...