Java8的HashMap扩容过程主要就是集中在resize()方法中

 final Node<K,V>[] resize() {
// ...省略不重要的
}

其中,当HashMap扩容完毕之后,需要对原有的数据进行转移。因为容量变大了,部分元素的位置因此要变更,因而出现了下面的这个转移过程。

转移过程大致是:依次从旧数组里取值,然后从该值对应的链表上依次取出节点,对节点取模分别放入lo链表和hi链表,当链表中节点遍历完后,分别把lo链表和hi链表放入新数组的不同位置。

在看到如下第15行时,我在想,为什么(e.hash & oldCap)== 0时就放入lo链表,否则就是hi链表?

说到这个问题,那我们就要回顾下HashMap存入新元素的过程了。看下面的第45行,可以发现插入时是使用(n - 1) & hash来计算位置的,即数组长度-1,而扩容移位是使用数组长度n计算的,那这是为什么呢?

 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;
}
}
}
} final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
// ...省略不重要的
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
// ...省略不重要的
}

像我们看Java8的HashMap源码,应该都应该知道HashMap的底层数组长度都是2的n方的值

那么我们就假设一个底层数组长度为8的HashMap模拟进行插入元素和扩容移位的过程

长度n=8 ---->    0x1000

n-1    ---->    0x0111

此时写入两个元素,两个元素的hash值分别为hash1 = 0x0101,hash2 = 0x1101

hash1 & n-1 = 0x0101

hash2  & n-1 = 0x0101

两个hash取模后的结果是一致的,所以它们会在同一个地方组成链表

那么此时如果要进行扩容移位呢?

hash1 & n = 0x0000

hash2 & n = 0x1000

此时两者的结果是不一样的,并且相差0x1000即10进制的8即数组长度.。

所以这也就是为什么上图15行只判断==0的原因,因为这个取模结果只有0和1两种值(数组长度是2的n次方,只有除了符号位外的最高位为1)

而两个取模结果等于数组长度,这也就是为什么上图第32和36行那么处理的原因。

Java8中HashMap扩容算法小计的更多相关文章

  1. java8中hashMap

    摘自:http://www.importnew.com/20386.html 简介 Java为数据结构中的映射定义了一个接口java.util.Map,此接口主要有四个常用的实现类,分别是HashMa ...

  2. java7,java8 中HashMap和ConcurrentHashMap简介

    一:Java7 中的HashMap 结构: HashMap 里面是一个数组,然后数组中每个元素是一个单向链表.链表中每个元素称为一个Entry 实例,Entry 包含四个属性:key, value, ...

  3. Java中HashMap扩容机制思考

    1. HashMap在什么条件下扩容 判断HashMap的数组Size大小如果超过loadFactor*capacity,就要扩容. 相关的类属性: capacity:当前数组容量,始终保持 2^n, ...

  4. jdk1.7中hashmap扩容时不会产生死循环

    在扩容时 transfer( ) 方法中 newTable 新数组 局部变量 table 旧数组 全局变量 当第一个链表进行while循环时 执行到 e.next = newTable[i]; 时 n ...

  5. JAVA8 中 LocalDateTime的使用小栗子

    LocalDate givenDate = LocalDate.parse("2019-04-23",DateTimeFormatter.ofPattern("yyyy- ...

  6. Java8中的HashMap分析

    本篇文章是网上多篇文章的精华的总结,结合自己看源代码的一些感悟,其中线程安全性和性能测试部分并未做实践测试,直接是“拿来”网上的博客的. 哈希表概述 哈希表本质上一个数组,数组中每一个元素称为一个箱子 ...

  7. Java7与Java8中的HashMap和ConcurrentHashMap知识点总结

    JAVA7 Java7的ConcurrentHashMap里有多把锁,每一把锁用于其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效的提高并发访问效率呢.这 ...

  8. 初探Java8中的HashMap(转)

    HashMap是我们最常用的集合之一,同时Java8也提升了HashMap的性能.本着学习的原则,在这探讨一下HashMap. 原理 简单讲解下HashMap的原理:HashMap基于Hash算法,我 ...

  9. Java7/8 中 HashMap 和 ConcurrentHashMap的对比和分析

    大家可能平时用HashMap比较多,相对于ConcurrentHashMap 来说并不是很熟悉.ConcurrentHashMap 是 JDK 1.5 添加的新集合,用来保证线程安全性,提升 Map ...

随机推荐

  1. this、对象原型

    this和对象原型 第一章 关于this 1.1 为什么要用this this 提供了一种更优雅的方式来隐式"传递"一个对象引用,因此可以将 API 设计 得更加简洁并且易于复用. ...

  2. 31、splice()用法

    改变数组,向数组中添加/删除元素: eg: 1.删除元素: let arr=['bob','lily','bike','sam']; arr.splice(2,1) console.log(arr) ...

  3. C# 7可以在.NET Framework 4上运行吗?

    https://stackoverflow.com/questions/42482520/does-c-sharp-7-0-work-for-net-4-5 To sum up: All of C# ...

  4. 【Maven】Maven之scope依赖范围

    一.理解Maven scope依赖范围的作用 Maven在编译项目主代码的时候需要使用一套classspath.总共有三种classpath,分别对应于Maven编译项目主代码的时候.Maven编译和 ...

  5. springboot+jndi+tomcat配置多数据源

    1.在application.properties中,添加jndi配置,如下图 2.新建dataSourceConfig类 3.dataSourceConfig类详细代码,这里只贴出其中一个,多个数据 ...

  6. Linux运维技术之LVM(逻辑卷管理)

    DM :逻辑设备(模块)--->LVM 优点: 个分区) 2.1.partprobe  /dev/sdb : 使用partprobe可以不用重启系统即可配合fdisk工具创建新的分区 2.2.c ...

  7. maven nexus 私服搭建 Windows版

    准备工作 已安装jdk,并配置好了环境变量 已安装maven,并配置好了环境变量 下载Nexus Repository OSS:https://www.sonatype.com/download-os ...

  8. java 的任意进制间转换(很方便)

    import java.util.Scanner; public class Main{ public static void main(String[] args) { Scanner sc = n ...

  9. PAT 乙级 1006.换个格式输出整数 C++/Java

    1006 换个格式输出整数 (15 分) 题目来源 让我们用字母 B 来表示“百”.字母 S 表示“十”,用 12...n 来表示不为零的个位数字 n(n < 1000),换个格式来输出任一个不 ...

  10. pandas知识点脑图汇总

    参考文献: [1]Pandas知识点脑图汇总