jdk1.8 HashMap的扩容resize()方法详解
/**
* Initializes or doubles table size. If null, allocates in
* accord with initial capacity target held in field threshold.
* Otherwise, because we are using power-of-two expansion, the
* elements from each bin must either stay at same index, or move
* with a power of two offset in the new table.
* @return the table
*
*
*
* 初始化或者翻倍表大小。
* 如果表为null,则根据存放在threshold变量中的初始化capacity的值来分配table内存
* (这个注释说的很清楚,在实例化HashMap时,capacity其实是存放在了成员变量threshold中,
* 注意,HashMap中没有capacity这个成员变量)
* 。如果表不为null,由于我们使用2的幂来扩容,
* 则每个bin元素要么还是在原来的bucket中,要么在2的幂中
*
* 此方法功能:初始化或扩容
*/
final Node<K,V>[] resize() {
Node<K,V>[] oldTab = table;
int oldCap = (oldTab == null) ? 0 : oldTab.length;
int oldThr = threshold;
//新的容量值,新的扩容阀界值
int newCap, newThr = 0;
//oldTab!=null,则oldCap>0
if (oldCap > 0) {
//如果此时oldCap>=MAXIMUM_CAPACITY(1 << 30),表示已经到了最大容量,这时还要往map中放数据,则阈值设置为整数的最大值 Integer.MAX_VALUE,直接返回这个oldTab的内存地址。
if (oldCap >= MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return oldTab;
}
//如果(当前容量*2<最大容量&&当前容量>=默认初始化容量(16))
//并将将原容量值<<1(相当于*2)赋值给 newCap
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
oldCap >= DEFAULT_INITIAL_CAPACITY)
//如果能进来证明此map是扩容而不是初始化
//操作:将原扩容阀界值<<1(相当于*2)赋值给 newThr
newThr = oldThr << 1; // double threshold
}
else if (oldThr > 0) // initial capacity was placed in threshold
//进入此if证明创建map时用的带参构造:public HashMap(int initialCapacity)或 public HashMap(int initialCapacity, float loadFactor)
//注:带参的构造中initialCapacity(初始容量值)不管是输入几都会通过 “this.threshold = tableSizeFor(initialCapacity);”此方法计算出接近initialCapacity参数的2^n来作为初始化容量(初始化容量==oldThr)
newCap = oldThr;
else { // zero initial threshold signifies using defaults
//进入此if证明创建map时用的无参构造:
//然后将参数newCap(新的容量)、newThr(新的扩容阀界值)进行初始化
newCap = DEFAULT_INITIAL_CAPACITY;
newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
}
if (newThr == 0) { //进入此if有两种可能
// 第一种:进入此“if (oldCap > 0)”中且不满足该if中的两个if
// 第二种:进入这个“else if (oldThr > 0)” //分析:进入此if证明该map在创建时用的带参构造,如果是第一种情况就说明是进行扩容且oldCap(旧容量)小于16,如果是第二种说明是第一次put
float ft = (float)newCap * loadFactor;
//计算扩容阀界值
newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
(int)ft : Integer.MAX_VALUE);
}
threshold = newThr;
@SuppressWarnings({"rawtypes","unchecked"})
Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
table = newTab;
//如果“oldTab != null”说明是扩容,否则直接返回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的实例
((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;//此对象接收会放在“j + oldCap”(当前位置索引+原容量的值)
Node<K,V> next;
do {
next = e.next;
//以下是扩容操作的核心,详情见我的博客:https://www.cnblogs.com/shianliang/p/9204942.html
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;
}
jdk1.8 HashMap的扩容resize()方法详解的更多相关文章
- 【Java】HashMap源码分析——常用方法详解
上一篇介绍了HashMap的基本概念,这一篇着重介绍HasHMap中的一些常用方法:put()get()**resize()** 首先介绍resize()这个方法,在我看来这是HashMap中一个非常 ...
- 一万三千字的HashMap面试必问知识点详解
目录 概论 Hasmap 的继承关系 hashmap 的原理 解决Hash冲突的方法 开放定址法 再哈希法 链地址法 建立公共溢出区 hashmap 最终的形态 Hashmap 的返回值 HashMa ...
- 【集合框架】JDK1.8源码分析之ArrayList详解(一)
[集合框架]JDK1.8源码分析之ArrayList详解(一) 一. 从ArrayList字表面推测 ArrayList类的命名是由Array和List单词组合而成,Array的中文意思是数组,Lis ...
- (转)Spring JdbcTemplate 方法详解
Spring JdbcTemplate方法详解 文章来源:http://blog.csdn.net/dyllove98/article/details/7772463 JdbcTemplate主要提供 ...
- C++调用JAVA方法详解
C++调用JAVA方法详解 博客分类: 本文主要参考http://tech.ccidnet.com/art/1081/20050413/237901_1.html 上的文章. C++ ...
- JAVA 注解的几大作用及使用方法详解
JAVA 注解的几大作用及使用方法详解 (2013-01-22 15:13:04) 转载▼ 标签: java 注解 杂谈 分类: Java java 注解,从名字上看是注释,解释.但功能却不仅仅是注释 ...
- Java提高篇——equals()与hashCode()方法详解
java.lang.Object类中有两个非常重要的方法: 1 2 public boolean equals(Object obj) public int hashCode() Object类是类继 ...
- Java构造和解析Json数据的两种方法详解二
在www.json.org上公布了很多JAVA下的json构造和解析工具,其中org.json和json-lib比较简单,两者使用上差不多但还是有些区别.下面接着介绍用org.json构造和解析Jso ...
- java基础(十六)----- equals()与hashCode()方法详解 —— 面试必问
本文将详解 equals()与hashCode()方法 概述 java.lang.Object类中有两个非常重要的方法: public boolean equals(Object obj) publi ...
随机推荐
- 深入浅出的webpack构建工具---HappyPack优化构建(九)
阅读目录 一:什么是HappyPack? 作用是什么? 二:如何在配置中使用HappyPack? 回到顶部 一:什么是HappyPack? 作用是什么? Webpack是允许在NodeJS中的,它是单 ...
- 深入浅出的webpack构建工具---devTool中SourceMap模式详解(四)
阅读目录 一:什么是SourceMap? 二:理解webpack中的SourceMap的eval,inline,sourceMap,cheap,module 三:开发环境和线上环境如何选择source ...
- 编写简单Linux内核模块
模块代码如下 //main.c #include <linux/kernel.h> #include <linux/module.h> #include <linux/i ...
- python线程和进程编程对比
import timefrom concurrent.futures import ThreadPoolExecutor,as_completedfrom concurrent.futures imp ...
- 错误:java.io.FileNotFoundException: /storage/emulated/0/Documents/eclipse-inst-win64.exe
在Android服务的最佳实例中:https://www.cnblogs.com/hh8888-log/p/10300972.html,在最后运行的时候,点击Start Download按钮总是会报一 ...
- java Switch中的case后面加上大括号({})和不加大括号的区别
java基础求真之switch 的case 后面加上大括号和不加大括号的区别. 下面给出三段代码大家看一下有什么不同以及哪段代码能够编译通过那段代码编译不能通过,为什么?(Why?) 代码片段一: i ...
- samba服务,连接远程开发机
到了新环境,自己的开发机需要通过跳板机连,每次登录跳板机都需要RSA动态密码.一开始让我迷惑的是,这有个跳板机,那怎么让本地代码和开发机代码同步呢.以前公司的情况,一个是不需要跳板机,在phpstor ...
- Luogu3232 HNOI2013 游走 高斯消元、期望、贪心
传送门 这种无向图上从一个点乱走到另一个点的期望题目好几道与高斯消元有关 首先一个显然的贪心:期望经过次数越多,分配到的权值就要越小. 设$du_i$表示$i$的度,$f_i$表示点$i$的期望经过次 ...
- JS-JS作用域问题
一. js没有块级作用域(可以自己闭包或其他方法实现),只有函数级作用域,函数外面的变量函数里面可以找到,函数里面的变量外面找不到. var a=10; function fn(){ console. ...
- DataWorks使用小结(二)——功能面板使用指南
一.数据开发 1.任务开发 新建表 野路子可以直接新建一个任务,粘贴DDL,手动运行任务即可完成建表 正常应当是在“数据管理”->数据表管理中建表: 支持可视化建表和DDL建表(配合之前的宏,建 ...