HashMap源码解析(二) HashMap的rehash操作:resize()函数

IDM更改下载路径的详细指南 Internet Download Manager(IDM)是一款功能全面的下载加速工具,它支持多种浏览器和协议,能够显著提升下载速度,同时提供断点续传、多线程下载等实用功能。IDM的用户界面简洁明了,操作便捷,使得用户能够轻松管理下载任务。此外,IDM还支持自动分类下载文件、定时下载等高级功能,进一步提升了用户的下载体验。通过本文的介绍,相信用户已经掌握了如何在IDM中更改下载路径的方法。这一功能不仅提升了下载效率和文件管理便捷性,还满足了用户的个性化需求。 阅读详情
final Node<K,V>[] resize() {
        Node<K,V>[] oldTab = table;
        // 获得老的容量,还没分配表的话为0
        int oldCap = (oldTab == null) ? 0 : oldTab.length;
        //threshold是扩容的阈值
        int oldThr = threshold;
        //新的threshold应该是老的两倍.
        int newCap, newThr = 0;
        //老的table不是null,就要判断一下要扩容到多大
        if (oldCap > 0) {
        	//太大了,不能扩容了,直接返回老的表继续用
            if (oldCap >= MAXIMUM_CAPACITY) {
                threshold = Integer.MAX_VALUE;
                return oldTab;
            }
            //还能扩容,那么将在后面进行扩容操作,这里只是把newCap赋值为oldCap的两倍,newThr赋值为oldThr的两倍
            else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                     oldCap >= DEFAULT_INITIAL_CAPACITY)
                newThr = oldThr << 1; // double threshold
        }
        //原table是null,新的容量threshold.  
        else if (oldThr > 0) // initial capacity was placed in threshold
            newCap = oldThr;
         //初始化map的大小为0,用默认值代替
        else {               // zero initial threshold signifies using defaults
            newCap = DEFAULT_INITIAL_CAPACITY;
            newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
        }
        // 第一次的threshold是要扩容到多大.但是之后的threshold是触发resize的阈值.所以第一次扩容(即的初始化table)之后,要把threshold设置为阈值而不再是扩容后的大小.
        if (newThr == 0) {
            float ft = (float)newCap * loadFactor;
            newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                      (int)ft : Integer.MAX_VALUE);
        }
        threshold = newThr;
        @SuppressWarnings({"rawtypes","unchecked"})
		//新建一个newCap大小的Node数组table来进行rehash
            Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
        table = newTab;
        //老table不是null进行扩容的话 要执行rehash操作,把老表的值都放到新表当中
        
        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<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;
                        }
                    }
                }
            }
        }
        return newTab;
    }

总结一下resize()里的操作逻辑:
主要有几个变量:

  1. Node<K,V>[] oldTab = table; 把老的table表放到oldTab引用,后面进行rehash操作
  2. int oldCap = (oldTab == null) ? 0 : oldTab.length; 老的table的大小,null的话就是0
  3. int oldThr = threshold; 老的阈值,阈值和容量分开存放,不用每次都要计算了.
  4. int newCap = 0;新的容量大小 ,初始化为0
  5. int newThr = 0;新的阈值大小, 初始化为0
    进行resize操作的过程(不考虑边界条件)

判断老的table是不是null(oldCap==0),是的话

把newCap也就是新的容量赋值为oldThr(table是null说明是第一次进行扩容,threshold被tableSizeFor设置为了2的幂次).然后把newThr也就是新的阈值赋值为(oldCap*装填因子).
如果传入的初始容量为0,就用默认值16代替.

否则的话(即不是第一次初始化table)

newCap赋值为oldCap的两倍,newThr赋值为oldThr的两倍

(上面的步骤主要是在计算应该扩容为多大)
之后将threshold赋值为newThr
新建一个newCap大小Node数组

如果老的table不是null,就要把老的Node全部复制到新的table里面

进行rehash操作
因为底层是使用Node数组实现的,而且数组大小已知为oldCap,所以直接遍历数组,对于不是null的数组元素(也就是有Node节点的元素)进行rehash重新找他们在新数组中的位置.

最后返回新的table数组

AI之KE:Knowledge Engineering知识工程的简介、发展、应用案例之详细攻略 AI之KE:Knowledge Engineering知识工程的简介、发展、应用案例之详细攻略 目录 Knowledge Engineering知识工程的简介 0.1、What 0.2、How 0.3、Why 1、知识工程过程的5个活动 2、知识图谱的应用 Knowledge Engineering知识工程的发展 1、前知识工程时期——1950-1970时期:图... 阅读详情

相关推荐

数据中心光模块升级实录:从200G QSFP56到400G QSFP-DD的踩坑指南

本文记录了数据中心从200G QSFP56升级至400G QSFP-DD光模块的完整实战经验。文章深入剖析了升级过程中面临的兼容性、链路预算、布线、散热与功耗管理等核心挑战,并提供了具体的解决方案与排坑指南,为高速网络升级提供了宝贵的实践参考。

butter的博客 479

HashMap之扩容&rehash详解

HashMap扩容

zhao6406879的博客 1890

CS1237卡尔曼滤波实战:如何用24位ADC实现电子秤级精度?

本文详细介绍了如何利用CS1237 24位ADC芯片结合卡尔曼滤波算法实现电子秤级精度测量。通过解析CS1237硬件特性、卡尔曼滤波原理及STM32驱动优化,提供了一套完整的解决方案,包括多通道支持、驱动代码实现和性能调优技巧,适用于工业测量和嵌入式开发领域。

linux的博客 1087

HashMap的ReHash图解

resize方法 void resize(intnewCapacity) { Entry[] oldTable = table; intoldCapacity = oldTable.length; ...... //创建一个新的Hash Table Entry[] newTable =new Entry[newCapacity]; //将Old H...

absolute_chen的博客 6447

GT-suite v2016的下载和安装

1 写在前面 GT-suite 是一款用来做内燃机仿真的软件。在安装过程中遇到很多问题,网上的安装教程也大都抄来抄去,试着安装了几遍都没有成功。最终在贴吧一个老哥的帖子里找到了解决办法,但是老哥的帖子也不是很详细,所以做了这个详细版本的教程。 GT-suite v2016安装包: 链接:https://pan.baidu.com/s/1JZPgJ8_-J-L8rV84-eHedQ 提取码:uj...

kisssshot的博客 3万+

Qoder Quest 模式实战:从需求到代码的自动化开发

本文深入探讨Qoder Quest模式如何实现从需求到代码的自动化开发。通过编写清晰的Spec规格说明,Qoder能智能分解任务并在后台执行,生成高质量代码,大幅提升开发效率,让开发者专注于架构设计等创造性工作。

herb5的博客 1151

HashMap的原理,底层数据结构,rehash的过程,指针碰撞问题

转载自-http://www.importnew.com/7099.html 先来些简单的问题 “你用过HashMap吗?” “什么是HashMap?你为什么用到它?” 几乎每个人都会回答“是的”,然后回答HashMap的一些特性,譬如HashMap可以接受null键值和值,而Hashtable则不能;HashMap是非synchronized;HashMap很快;以及HashM

勇气与行动 7131

浅析ArcGis中的软件——ArcMap、ArcScene、 ArcGlobe、ArcCatalog

ArcMap:是集空间数据显示、矢量数据编辑、冲突数据检查(拓扑检查)、查询检索(地理编码)、统计(字段属性表)、报表生成、空间分析(ArcGIS Spatial Analyst)和高级制图(制图表达)等众多功能干一体的桌面应用平台软件。而且提供所见即所得的符号编辑器,令用户可以随心所欲地生成任意复杂的点、线、面符号。所支持的空间数据格式包括Arclnfo coverages、ESRI shapefiles、ArcSDE lavers、DXF、DWG、DGN、常见的图像格式、GRIDs、TINs等。

lxlmycsdnfree的博客 6563

【Java】HashMap实现原理分析(源码分析,ReHash,扩容机制)

目录 一、HashMap的数据结构 解决hash冲突的办法 二、源码分析 1.位桶数组 2.数组元素Node实现了Entry接口,v> 3.HashMap如何put(key,value) 4.HashMap如何getValue值 5.HasMap的扩容机制resize(); 6. JDK1.8使用红黑树的改进 三、再谈ReHash 单线程下的ReHash ...

康师傅没有眼泪 4582

MTK Linux DRM分析(十一)- MTK KMS Panel显示屏驱动

面板扩展(Panel Extension)是指 MediaTek 在标准 DRM 面板驱动框架之上添加的定制化功能模块。

iTom1900 1684

西门子PLC新手必看:200SMART与1200/1500的MODBUS RTU通讯实战(附完整配置流程)

本文详细解析了西门子PLC中S7-200 SMART与S7-1200/1500之间实现MODBUS RTU通讯的完整实战流程。内容涵盖硬件接线、软件配置及程序编写,重点讲解了200SMART作为从站、1200/1500作为主站的典型架构,并提供了关键功能块的使用方法和常见问题排查技巧,帮助新手快速打通不同系列PLC间的数据交换。

weixin_29214559的博客 393

HashMap图文源码解析

反观长度16或者其他2的幂,Length-1的值是所有二进制位全为1,这种情况下,index的结果等同于HashCode后几位的值。可以为null,但是不能为可变对象,如果是可变对象,对象中的属性改变,那么Hash也要进行相应的改变,导致下次五大找到已存在的Map中的数据。但是,因为HashMap的长度是有限的,当插入的Entry越来越多时,再完美的Hash函数也难免会出现index冲突的情况。第二步:我们查看的是Next节点Entry1,Entry1的Key是apple,正是我们要找的结果。

echola_mendes的博客 834

15、虚拟环境中的数据保护与恢复方案解析

本文深入解析了虚拟环境中两种重要的数据保护与恢复解决方案:RecoverPoint for Virtual Machines(RP4VM)在VxRail上的设计,以及Veeam Backup & Replication(VBR)与VxRail的集成方案。文章详细介绍了RP4VM的网络布局、故障转移场景及其相关问题,以及VBR的架构设计、备份与复制流程、许可证选项及其多平台支持特性。此外,还探讨了RP4VM与VBR结合使用的综合解决方案,以及未来数据保护领域的发展趋势,如智能化管理、云原生集成和零信任架构,为

t4y5u6i7o的博客 95

JDK集合源码之HashMap解析(下)

由于上篇文章JDK集合源码之HashMap解析(上)篇幅较长,为阅读方便,分成两篇博客来分析HashMap! 5.HashMap的成员方法 5.1put(K key, V value)方法 put方法是比较复杂的,实现步骤大致如下: 先通过 hash 值计算出 key 映射到哪个桶; 如果桶上没有碰撞冲突,则直接插入; 如果出现碰撞冲突了,则需要处理冲突: a 如果该桶使用红黑树处理冲突,则调用红黑树的方法插入数据; b 否则采用传统的链式方法插入。如果链的长度达到临界值,则把链转变为红黑树;

兴趣使然的草帽路飞 1万+

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

HashMap 添加元素put()的源码和扩容方法resize()的源码解析

HashMap 添加元素put()的源码和扩容方法resize()的源码解析。

qq_43857727的博客 451

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

绝了!这是我见过最详细的HashMap源码解析

HashMap是基于哈希表实现的,每一个元素是一个key-value对,其内部通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动增长.HashMap是非线程安全的,只适用于单线程环境,多线程环境可以采用并发包下的HashMap 实现了Serializable接口,因此它支持序列化,实现了Cloneable接口,能被克隆HashMap是基于哈希表的Map接口的非同步实现.此实现提供所有可选的映射操作,并允许使用null值和null键.此类不保证映射的顺序,特别是它不保证该顺序恒久不变.

好好学java 2513

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

rehash 方法

protected void rehash() { int oldCapacity = table.length; Entry<?,?>[] oldMap = table; List item //扩容扩为原来的两倍+1 int newCapacity = (oldCapacity << 1) + 1; //判断是否超过最大容量 if (newCapacity - M...

weixin_44540580的博客 1184

让星星⭐月亮告诉你,HashMap的resize()即扩容方法源码解读(已重新完善,如有不足之处,欢迎指正~)

分析HashMap的resize()即扩容方法的源码,会发现主要分两部分操作: 为创建新数组初始化新数组容量和新数组扩容阈值; 创建新数组后,需将旧数组数据转移到新数组上来 具体,详见下述的源码解析: /**HashMap的resize()方法*/ /** * Initializes or doubles table size. If null, allocates in * accord with initial capacity target held in field thr

Dylaniou的博客 370

JDK8_HashMap PUT和RESIZE操作

1. put操作 源码 /** * Implements Map.put and related methods. * * @param hash hash for key * @param key the key * @param value the value to put * @param onlyIfAbsent if true, don't change existing value * @param evict.

weianluo的博客 416

hashmap1.8 详情解析

文章目录前言HashMap的数据结构深入源码两个参数成员变量四个构造方法插入数据的方法:put()哈希函数:hash()动态扩容:resize()节点树化、红黑树的拆分节点树化红黑树拆分总结心得 前言 今天我们来学习Java中较为常用的集合类 HashMap。 另外说明一下,本文的 HashMap 源码是基于Jdk1.8版本的,如果没有特别说明的话,...

wzh70190的博客 652

看源码之HashMap

先扯点别的:听说拳皇97界的大魔王老K退役了,不知道以后还能不能见到那么犀利的大门。最近感觉自己的拳皇水平有点提升,应该能排到100多线的水平吧。 今天记录一下看HashMap源码的过程,感觉HashMap的源码要比ArrayList难一点。所以只看主要流程,不可能每一行代码都搞懂什么意思。 先看一下HashMap的继承结构图 HashMap:它根据键的hashCode值存储数据,大多数...

leilifengxingmw的博客 1096

别再死记硬背了!动手调试JDK8 HashMap源码,亲眼看看rehash时链表怎么‘分家’

本文通过IntelliJ IDEA调试实战,深入解析JDK8 HashMap在rehash时链表拆分的动态过程。从环境搭建到关键位运算分析,详细展示了链表如何被拆分为高低位两个子链表,并迁移到新数组位置。文章结合具体代码示例和调试技巧,帮助开发者直观理解HashMap扩容机制,提升对Java集合框架的掌握深度。

weixin_30485379的博客 356

深入理解 Java HashMap 扩容机制:从源码到原理全解析

过小(如 0.5):扩容频繁,空间浪费多,但冲突少过大(如 1.0):内存利用率高,但冲突多,链表变长,查询慢0.75:在泊松分布下,桶中元素碰撞概率较低,综合性能最优官方注释中也提到,在理想随机 hash 下,0.75 的负载因子使得链表长度超过 8 的概率约为 0.00000006,极低。要点说明触发条件扩容倍数新容量 = 旧容量 × 2迁移优化高位 bit 判断,避免重新 hash链表/树处理拆分为高低位两组,按长度决定链表或树线程安全。

chagumu 417

Java HashMap中在resize()时候的rehash,即再哈希法的理解

HashMap的扩容机制---resize() 虽然在hashmap的原理里面有这段,但是这个单独拿出来讲rehash或者resize()也是极好的。 什么时候扩容:当向容器添加元素的时候,会判断当前容器的元素个数,如果大于等于阈值(知道这个阈字怎么念吗?不念fa值,念yu值四声)---即当前数组的长度乘以加载因子的值的时候,就要自动扩容啦。 扩容(resize)...

weixin_30698527的博客 252

hashmap源码-扩容机制

前言 注意,本系列文章都是基于 jdk 1.8 这是 hashmap 源码系列文章的第三篇,前面文章讲解了 hash 算法,以及元素 put, get 的流程,相信大家对 hashmap 容器已经有了大体上的认识,今天要讲的内容可谓是 hashmap 的重头戏——扩容机制。 内容主要涉及: 容器扩容 负载因子 扩容机制 容器扩容 jdk 中很多容器的底层实现使用的是数组,比如 ArrayList,还有今天要说的 Hashmap。数组的容量是一开始指定好的,为一组连续的内存空间。 在实际的开发过程中

qq_34679704的博客 450

HashMap

HashMap是由数组+链表组成的 JDK1.8之后是数组+链表+红黑树 HashMap的实现原理 HashMap是一个用于存储Key-Value键值对的集合, 每一个键值对也叫做Entry. 这些个键值对(Entry)分散存储在一个数组当中, 这个数组就是HashMap的主干. HashMap数组每一个元素的初始值都是Null. 对于HashMap, 我们最常使用的是两个方法:Get和Put. Put方法的原理 调用Put方法的时候发生了什么? 比如调用hashMap.put(“apple”,0), 插入

mhhhb的博客 1959
上一篇: HashMap源码解析(零) HashMap类的源码注释介绍
下一篇: HashMap里面的散列函数是什么
codexjli
博客等级 码龄11年 2粉丝 19原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值