/**
* 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()方法详解的更多相关文章

  1. 【Java】HashMap源码分析——常用方法详解

    上一篇介绍了HashMap的基本概念,这一篇着重介绍HasHMap中的一些常用方法:put()get()**resize()** 首先介绍resize()这个方法,在我看来这是HashMap中一个非常 ...

  2. 一万三千字的HashMap面试必问知识点详解

    目录 概论 Hasmap 的继承关系 hashmap 的原理 解决Hash冲突的方法 开放定址法 再哈希法 链地址法 建立公共溢出区 hashmap 最终的形态 Hashmap 的返回值 HashMa ...

  3. 【集合框架】JDK1.8源码分析之ArrayList详解(一)

    [集合框架]JDK1.8源码分析之ArrayList详解(一) 一. 从ArrayList字表面推测 ArrayList类的命名是由Array和List单词组合而成,Array的中文意思是数组,Lis ...

  4. (转)Spring JdbcTemplate 方法详解

    Spring JdbcTemplate方法详解 文章来源:http://blog.csdn.net/dyllove98/article/details/7772463 JdbcTemplate主要提供 ...

  5. C++调用JAVA方法详解

    C++调用JAVA方法详解          博客分类: 本文主要参考http://tech.ccidnet.com/art/1081/20050413/237901_1.html 上的文章. C++ ...

  6. JAVA 注解的几大作用及使用方法详解

    JAVA 注解的几大作用及使用方法详解 (2013-01-22 15:13:04) 转载▼ 标签: java 注解 杂谈 分类: Java java 注解,从名字上看是注释,解释.但功能却不仅仅是注释 ...

  7. Java提高篇——equals()与hashCode()方法详解

    java.lang.Object类中有两个非常重要的方法: 1 2 public boolean equals(Object obj) public int hashCode() Object类是类继 ...

  8. Java构造和解析Json数据的两种方法详解二

    在www.json.org上公布了很多JAVA下的json构造和解析工具,其中org.json和json-lib比较简单,两者使用上差不多但还是有些区别.下面接着介绍用org.json构造和解析Jso ...

  9. java基础(十六)----- equals()与hashCode()方法详解 —— 面试必问

    本文将详解 equals()与hashCode()方法 概述 java.lang.Object类中有两个非常重要的方法: public boolean equals(Object obj) publi ...

随机推荐

  1. Luogu P2661 [NOIP2015] 信息传递

    qwq 今天做完并查集突然想起来这道以前做的好(shui)题, 虽然是黄题,但是是并查集一个比较特别的用法 这道题大概可以用求最小环的方式来做,但是从直觉上果然还是并查集w 乍一看只要求出“父→子”即 ...

  2. node通过http.request向其他服务器上传文件

    function upload(callback) { let boundaryKey = '----' + new Date().getTime(); // 用于标识请求数据段 let option ...

  3. linux系统原子操作

    一.概念 原子操作提供了指令原子执行,中间没有中断.就像原子被认为是不可分割颗粒一样,原子操作(atomic operation)是不可分割的操作.      c语言中一个变量的自加1操作,看起来很简 ...

  4. javascript闭包的使用--按钮切换

    闭包实现按钮状态切换 看下面的代码: var toggleBtn = document.getElementById('toggle'); var toggleFun = (function() { ...

  5. 解决webapi首次启动速度慢的问题 - z

    原理与下面两篇文章提及的相同 https://blog.csdn.net/godcyx/article/details/38517135 http://www.huaface.com/p/12

  6. Ionic 安装JPush过程

    1.在官网注册App帐号,完成后会生成对应的AppKey 2. 进行在线安装 cordova plugin add https://github.com/jpush/jpush-phonegap-pl ...

  7. Luogu P1337 [JSOI2004]平衡点 / 吊打XXX

    一道入门模拟退火的经典题,还是很考验RP的 首先我们发现神TM这道题又和物理扯上了关系,其实是一道求广义费马点的题目 首先我们可以根据物理知识得到,当系统处于平衡状态时,系统的总能量最小 又此时系统的 ...

  8. RDMA技术解析

    文章出处:https://mp.weixin.qq.com/s/pW-tQR4AYr1Gtd4dpHVW7w 摘要:远程直接内存访问(即Remote Direct Memory Access)是一种直 ...

  9. Redis Cluster日常操作命令梳理

    在之前的一篇文章已经介绍了Redis Cluster及其部署,下面说下Redis Cluster日常操作命令: 一.以下命令是Redis Cluster集群所独有的,执行下面命令需要先登录redis: ...

  10. 002-打开文件管理规范-20190406.bat

    rem 002-打开文件管理规范-20190406.bat start /max https://www.cnblogs.com/delphixx/p/10652763.htmlcopy %~0 C: ...