hashMap扩容

什么时候扩容:当向容器添加元素的时候,会判断当前容器的元素个数,如果大于等于阈值---即当前数组的长度乘以加载因子的值的时候,就要自动扩容啦。

扩容(resize):当HashMap对象内部的数组无法装载更多的元素时,对象就需要扩大数组的长度,以便能装入更多的元素。Java里的数组是无法自动扩容的,所以使用一个新的数组代替已有的容量小的数组。

resize就是使用一个容量更大的数组来代替已有的容量小的数组,transfer()方法将原有Entry数组的元素拷贝到新的Entry数组里。如果发生了hash冲突,使用单链表的头插入方式,同一位置上新元素总会被放在链表的头部位置,这样先放在一个索引上的元素终会被放到Entry链的尾部。在旧数组中同一条Entry链上的元素,通过重新计算索引位置后,有可能被放到了新数组的不同位置上。

rehash使用的是2次幂的扩展(指长度扩为原来2倍),经过rehash之后,元素的位置要么是在原位置,要么是在原位置再移动2次幂的位置

Jdk1.7 hash(){return key % table.length;}

JDK1.8的优化

                 // 原索引
51                         if ((e.hash & oldCap) == 0) {
52                             if (loTail == null)
53                                 loHead = e;
54                             else
55                                 loTail.next = e;
56                             loTail = e;
57                         }
58                         // 原索引+oldCap
59                         else {
60                             if (hiTail == null)
61                                 hiHead = e;
62                             else
63                                 hiTail.next = e;
64                             hiTail = e;
65                         }

JDK1.7中rehash的时候,旧链表迁移新链表的时候,如果在新表的数组索引位置相同,则链表元素会倒置,JDK1.8不会

时间: 2025-01-07 11:32:08

hashMap扩容的相关文章

JDK1.8 HashMap 扩容 对链表(长度小于默认的8)处理时重新定位的过程

关于HashMap的扩容过程,请参考源码或百度. 我想记录的是1.8 HashMap扩容是对链表中节点的Hash计算分析. 对术语先明确一下: hash计算指的确定节点在table[index]中的链表位置index,不是节点的hash值. 1 Node<K,V> loHead = null, loTail = null; //这两个是记录重新hash计算后仍在原位置(设为index)的节点 2 Node<K,V> hiHead = null, hiTail = null; //这

HashMap 扩容分析

使用HashMap时我们需要注意一下几点问题: 1.HashMap是常用的Java集合之一,是基于哈希表的Map接口的实现.与HashTable主要区别为不支持同步和允许null作为key和value.  2.HashMap非线程安全,即任一时刻可以有多个线程同时写HashMap,可能会导致数据的不一致.  3.如果需要满足线程安全,可以用 Collections的synchronizedMap方法使HashMap具有线程安全的能力,或者使用ConcurrentHashMap.  4.在JDK1

Java8中HashMap扩容算法小计

Java8的HashMap扩容过程主要就是集中在resize()方法中 1 final Node<K,V>[] resize() { 2 // ...省略不重要的 3 } 其中,当HashMap扩容完毕之后,需要对原有的数据进行转移.因为容量变大了,部分元素的位置因此要变更,因而出现了下面的这个转移过程. 转移过程大致是:依次从旧数组里取值,然后从该值对应的链表上依次取出节点,对节点取模分别放入lo链表和hi链表,当链表中节点遍历完后,分别把lo链表和hi链表放入新数组的不同位置. 在看到如下

HashMap 扩容 加载因子

HashMap: public HashMap(int initialCapacity, float loadFactor) { //初始容量不能<0 if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); //初始容量不能 > 最大容量值,HashMap的最大容量值为2^30 if (initialCapa

HashMap 扩容

不难看出,loHead和loTail两个节点分别记录不需要移动的链表的头部和尾部,hiHead和hiTail分别记录需要移动的链表头部和尾部. 假设在扩容的时候某个数组下有这样一个链表 : image 其中,假设天蓝色部分的不需要挪动,红色部分的需要挪动 第一步 : 建立loHead loTail hiHead hiTail四个节点 第二步 : image 第三步 : image ... 第N步 : image 最后一步 : 把以loHead为首的链表放到数组的原位置,把以hiHead为首的链表

Java HashMap 扩容过程分析

1 final Node<K, V> resize(){ 2 3 // 用于存储重新散列后的数组 4 Node<K, V>[] newTab; 5 6 // 如果原来的数组是空的,则resize执行的是初始化操作,而不是扩容操作 7 if(table == null){ 8 // 初始容量为16 9 int cap = DEFAULT_CAPACITY;// 1<<<4 10 11 // 初始的加载因子为0.75,即容量使用到3/4时就要再次扩容 12 loadF

HashMap源码阅读(2)- 碰撞(冲突)与扩容

上次在 HashMap源码阅读(1)- 初始值.数据结构.hash计算一文中描述了hashMap的初始大小,底层存储结构,以及哈希值计算和index计算,本文将接着上文,继续深入了解HashMap中hash碰撞和扩容问题 1)hash碰撞 谈hash,不得不提的当然是hash碰撞的问题,所谓hash碰撞,简单地说即由不同的key所计算出相同的hash值.笔者才疏学浅,所掌握的解决hash碰撞的方式有以下几种: 1.开放地址法: 当冲突发生时,使用某种探查(亦称探测)技术在散列表中形成一个探查(测

HashMap的resize自动扩容

在之前学习的HashMap触发红黑树条件的知识点中,有一个步骤是resize(), 再来了解一下这块的知识 HashMap是JAVA最常用的集合之一,用来存储Key-Value这种键值对形式的数据,内部通过哈希表,让存取的效率最好的时候可以达到O(1),实际使用中可能存在hash冲突,引入了链表和红黑树结构,让效率最差也不低于O(logn). 集合的底层是基于数组.链表这种基础的数据结构,集合在容量不足的情况下,会触发动态扩容来保证有足够的空间存储数据,动态扩容因为涉及到一系列 数据调整拷贝等,

HashMap原理-1.7

之所以分两篇文章记录,因为之前一直看的1.7的源码,而且网上很多的都是关于1.7的,今天在1.8上打开源码一看,居然懵了.    没想到1.8的实现变化这么大.所有特地拿一篇文章来记录下. 本章只介绍1.7的情况 1.HashMap存储结构 哈希表是由数组+链表组成的,一个长度为16的数组中,每个元素存储的是一个链表的头结点.那么这些元素是按照什么样的规则存储到数组中呢.一般情况是通过hash(key)%len获得,也就是元素的key的哈希值对数组长度取模得到.比如上述哈希表中,12%16=12