最近在研究hashmap的扩容机制,作为一个小白,相信我的理解,对于一些同样是刚刚接触hashmap的白白是有很很大的帮助,毕竟你去看一些已经对数据结构了解透彻的大神谈hashmap的原理等,人家说的很高大上,时不时会夹着稍许的英文你也看不懂是吧,不过这样显得比较有逼格哈哈。在正文之前,我非常有必要给刚刚接触hashmap以及没有学过数据结构(其实数据结构我了解也不多哈哈)的小伙伴普及几个知识,你记住就行了:

  1. 对于刚接触hashmap,hashmap你就暂时理解为哈希表(hash表),结构为“数组+链表”;如果说到表的长度,那指的是数组长度。

  2. “数组+链表”的结构专业术语叫“链表散列”,说简单点,一个数组上的每个位置存储的一个单链表;实际上数组的每个位置记录着是单链表的第一个节点,有了第一个节点后面不就串起来了嘛

  3. hashmap在jdk1.8前的结构是“数组+(单)链表”,在jdk1.8,结构就引入了“数组+链表+红黑树”,不过在这里我们只讨论1.8之前

  4. hashmap在添加元素时使用的是“尾插法”,而在扩容时转移数据使用的是“头插法”;后半句话给我重点记着,后面的源码就涉及到这个

  5.hashmap扩容的本质是重新创建一个原有数组长度2倍的新数组。

  6. 新表的节点分布 并不一定 跟 旧表 一致。比如说旧表的oldTable[0]上有key(0)->key(1)->key(2),而到新表这里newTable[0]就可能变成了key(2)->key(0)【头插法】,而key(1)在其他位置了。

  好了,开始进入正题!我们来研究jdk1.8前的hashmap的扩容原理(为什么没有1.8呢?因为我还没去看哈哈);它扩容最核心的方法就是resize(),源码如下:

//hashmap的扩容方法
void resize(int newCapacity) {
Entry[] oldTable = table; //把当前的hash表赋值给一个临时数组,这个临时数组代表 旧hash表
int oldCapacity = oldTable.length; //得到旧hash表的长度
if (oldCapacity == MAXIMUM_CAPACITY) { //如果判断旧hash表的长度(其实是数组长度)等于最大容量值
threshold = Integer.MAX_VALUE; //把Integer.MAX_VALUE赋值给当前的阈值,它的意思就是不再扩容了
return;
} Entry[] newTable = new Entry[newCapacity]; //创建一个新的hash表
transfer(newTable, initHashSeedAsNeeded(newCapacity)); //这个是重点,这个方法实现将旧hash表的数据放到新的hash表中
table = newTable; //当前的hash表换成新的hash表了
threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1); // 有新表后,阈值是需要重新计算的
}

  

  上面代码中,我们真正要关注的是transfer(),你看它方法名就取得很明显,转移的意思是吧,源码如下:

   /**
* 把 旧表 的 数据 往新表上挪
*/
void transfer(Entry[] newTable, boolean rehash) {
int newCapacity = newTable.length; //得到新表的长度
for (Entry<K,V> e : table) { //这里table是旧表,这里是遍历旧表,把旧表的数据往新表上转移
while(null != e) { //如果当前节点不为空
Entry<K,V> next = e.next; //next是一个临时变量,用来引用或保存当前节点指向的下一节点,比如说当前节点是key(3),key(3)->key(5),
                            那next就暂时保存key(5)
if (rehash) { //重新计算hash
e.hash = null == e.key ? 0 : hash(e.key);
}
int i = indexFor(e.hash, newCapacity); //这个挺重要的,它是重新计算我们当前的(旧)节点应该放到新表的哪个位置上
e.next = newTable[i]; //超级重点,它的作用是断开当前节点与旧表的联系,啥意思呢? 还是刚才的例子当前节点是key(3),key(3)->key(5),
                          key(3)现在不指向key(5)了,已经投奔(指向)新表上的某个位置了

newTable[i] = e; //超级重点+,头插法来了,把当前的节点赋值给新表的某个位置,作用就是旧节点复制到新表上了;意思是每轮循环的当前节点都会
                         插入到新数组上的某个单链表的第一个位置,作为单链表的头节点

e = next; //把刚才保存的下一节点 作为下一轮循环的当前节点
}
}
}

  我尽量把解释都放到了源码上面,方便大家查看,减少不必要的页面上下滚动带来的眼睛疲劳(我真是活雷锋哈哈),后面我会去看jdk1.8的源码,会再次为大家分享。

  如果觉得说的勉强还行的话,点个推荐呗!

JDK1.8前_HashMap的扩容机制原理的更多相关文章

  1. HashMap底层结构、原理、扩容机制

    https://www.jianshu.com/p/c1b616ff1130 http://youzhixueyuan.com/the-underlying-structure-and-princip ...

  2. HashMap原理(二) 扩容机制及存取原理

    我们在上一个章节<HashMap原理(一) 概念和底层架构>中讲解了HashMap的存储数据结构以及常用的概念及变量,包括capacity容量,threshold变量和loadFactor ...

  3. HashSet保证元素唯一原理以及HashMap扩容机制

    一.HashSet保证元素唯一原理: 依赖于hashCode()和equals()方法1.唯一原理: 1.1 当HashSet集合要存储元素的时候,会调用该元素的hashCode()方法计算哈希值 1 ...

  4. ConcurrentHashMap的扩容机制(jdk1.8)

    ConcurrentHashMap相关的文章网上有很多,而关于ConcurrentHashMap扩容机制是很关键的点,尤其是在并发的情况下实现数组的扩容的问题经常会碰到,看到这篇写的具有代表性,详细讲 ...

  5. 深入理解HashMap的扩容机制

    什么时候扩容: 网上总结的会有很多,但大多都总结的不够完整或者不够准确.大多数可能值说了满足我下面条件一的情况. 扩容必须满足两个条件: 1. 存放新值的时候当前已有元素的个数必须大于等于阈值 2. ...

  6. HashMap的扩容机制以及默认大小为何是2次幂

    HashMap的Put方法 回顾HashMap的put(Key k, Value v)过程: (1)对 Key求Hash值,对n-1取模计算出Hash表数组下标 (2)如果没有碰撞,直接放入桶中,即H ...

  7. 【数组】- ArrayList自动扩容机制

    不同的JDK版本的扩容机制可能有差异 实验环境:JDK1.8 扩容机制: 当向ArrayList中添加元素的时候,ArrayList如果要满足新元素的存储超过ArrayList存储新元素前的存储能力, ...

  8. HashSet扩容机制在时间和空间上的浪费,远大于你的想象

    一:背景 1. 讲故事 自从这个纯内存项目进了大客户之后,搞得我现在对内存和CPU特别敏感,跑一点数据内存几个G的上下,特别没有安全感,总想用windbg抓几个dump看看到底是哪一块导致的,是我的代 ...

  9. ext文件系统机制原理剖析

    本文转载自ext文件系统机制原理剖析 导语 将磁盘进行分区,分区是将磁盘按柱面进行物理上的划分.划分好分区后还要进行格式化,然后再挂载才能使用(不考虑其他方法).格式化分区的过程其实就是创建文件系统. ...

随机推荐

  1. URL的字符编码

    摘要: 在通过URL访问HTTP SERVER的时候,通常会产生trace callback的异常,返回505的错误," VERSION IS NOT SUPPORTED ?" , ...

  2. UGUI核心元素、基本控件、复合控件和高级控件

    UGUI的核心元素: Anchor(锚点):每个控件都有一个Anchor属性,控件的4个顶点,分别与Anchor的4个点保持不变的距离,不受屏幕分辨率变化的影响. 系统默认设置控件的Anchor位置在 ...

  3. Unity资源引用问题

    前几天做项目时,遇到一个奇怪的问题: 从一处复制了一个预制体,预制体上面还附有一个材质球,材质球上关联着另一张贴图. 将所有关联的东西,均Copy两份,然后关联成一个新的预制体,最后用项目内的读取内存 ...

  4. JVM内存区域以及各区域的内存溢出异常,内存分代策略,垃圾收集算法,各种垃圾收集器

    本文整理自周志明老师的<深入理解Java虚拟机-JVM高级特性与最佳实践>第3版的第二章和第三章. 加上了一些网上拼拼凑凑的图片,个人认为很多博客复制来复制去,最后的东西都看不懂,所以从书 ...

  5. HDU - 5775-Bubble Sort(权值线段树)

    P is a permutation of the integers from 1 to N(index starting from 1). Here is the code of Bubble So ...

  6. 关于Vuex的那些事儿

    vuex vuex是一个专门为Vue.js应用程序开发的状态管理模式,集中式的存储应用的所有组件的状态 以相应的规则保证状态以一种可预测的方式发生变化 单向数据流 State:驱动应用的数据源(单向数 ...

  7. js 向上滚屏

    <!doctype html><html><head><meta charset="utf-8"><title>< ...

  8. 2020年 .NET ORM 完整比较、助力选择

    .NET ORM 前言 为什么要写这篇文章? 希望针对 SEO 优化搜索引擎,让更多中国人知道并且使用.目前百度搜索 .NET ORM 全是 sqlsugar,我个人是无语的,每每一个人进群第一件事就 ...

  9. 如何用canvas拍出 jDer's工作照

    背景 在京东,就职满五年的老员工被称作"大佬",如果满了十年,那就要被称之为"超级大佬"了. 从 2016 年 5 月 19 日开始,每一年的这一天都被定为京东 ...

  10. Spring AOP-用代理代替繁琐逻辑

    Spring AOP 基础概念 AOP 是一种面向切面的编程思想,通俗来讲,这里假如我们有多个方法. @Component public class Demo { public void say1() ...