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

基于PCIe的NVMe协议在FPGA中实现方法 NVMe协议是工作在PCIE的最上层协议层的,故需要先搞清楚PCIE。本文基于Xilinx的UltraScale+,开发工具为Vivado2021.2。NVMe的学习仍以spec为主,其它资料辅助理解,有冲突时以spec为准,必要时可对比最新版本spec。(此文重点介绍学习方法及资料,有时间再加细节)。 主要参考的文章是《老男孩读PCIe》,同时参考《古猫先生》,重点学习TLP报文部分,数据链路层和物理层的内容可以先不看。再买一本书《PCI Express 体系结构导读-王齐》用来查阅做笔记。 阅读详情
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数组

手把手教你学Simulink--四翼无人机滑模控制器设计与仿真 四翼无人机(Quadcopter)滑模控制(Sliding Mode Control, SMC)是一种鲁棒性很强的非线性控制方法,特别适用于存在模型不确定性和外部扰动的情况。滑模控制器通过强制系统状态进入并保持在一个预定义的滑模面上,从而实现对期望轨迹或姿态的精确跟踪。在这个教程中,我们将使用MATLAB和Simulink来设计并仿真一个基于滑模控制策略的四翼无人机系统。 阅读详情

相关推荐

2026 具身智能 VLA/WAM 全栈学习与训练路线:从动作建模、SFT、RL 到世界模型的 RTX PRO 6000 96GB 单卡实战指南

我会把这张表做成“”而不是只列论文名:先核对每个模型截至的公开代码、训练目标和数据接口,再单独给你一套。对于没有公开、只有推理代码或训练细节不完整的模型,我会明确标出来,避免把“论文里提到”误写成“可复现”。目前有一个重要更新:。截至今天 NVIDIA 官方开源主线已经是换成 Cosmos-Reason2-2B/Qwen3-VL 架构,动作端仍是连续路线,而且官方明确给出单卡微调时默认只训练,峰值显存约。所以你的 96GB 单卡对 GR00T SFT 非常宽裕。可以。下面我按,把它整理成一张真正面向“

u013250861的博客 444

HashMap之扩容&rehash详解

HashMap扩容

zhao6406879的博客 1890

基于Simulink的二相混合式步进电机驱动器快速建模与仿真实践

本文详细介绍了如何利用Simulink对二相混合式步进电机驱动器进行快速建模与仿真。通过从零搭建电机数学模型、设计H桥控制逻辑,并集成步进时序,手把手指导读者创建可运行的仿真模型文件。该方法能有效验证控制策略,避免硬件调试风险,是学习与实践电机驱动开发的理想途径。

weixin_29171087的博客 147

HashMap的ReHash图解

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

absolute_chen的博客 6447

19、CATIA V5:参数化建模与零件目录创建全解析

本文详细解析了在CATIA V5中通过设计表实现参数化建模及零件目录创建的完整流程。以支撑块和钩形夹为例,介绍了参数识别、设计表创建与关联、配置管理以及零件目录的构建方法。同时,提供了实际操作建议和注意事项,帮助设计师高效创建和管理零件族,提升设计效率和质量。

raspberrypi5的博客 447

基于SC、SCL、BP、SCAN和SSC的译码算法及Matlab代码

本文将介绍几种常见的译码算法,包括SC(Successive Cancellation)、SCL(Successive Cancellation List)、BP(Belief Propagation)、SCAN(Soft-Input Soft-Output Successive Cancellation)、SSC(Stacked Successive Cancellation)的原理,并提供相应的Matlab代码实现。以上是基于SC、SCL、BP、SCAN和SSC的译码算法的Matlab代码示例。

ByteWhisper的博客 946

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

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

勇气与行动 7131

十五、SAP-物料需求计划(MRP)

业务逻辑、功能讲解、图文解析、章节总结

m0_72403327的博客 1092

【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

目标检测YOLO实战应用案例100讲-基于激光雷达点云的三维目标检测算法研究

近几年来,在计算机视觉领域,利用深度学习卷积神经网络技术来实现各种任务的算法越来越多。毫米波雷达、相机、激光雷达、超声波雷达等车载传感器生产成本的降低,汽车的自动驾驶技术得到了飞速发展,在我们的日常生活中经常能看到该技术辅助汽车驾驶员进行行车。和非自动驾驶汽车相比,自动驾驶汽车存在诸多优点,如进一步减少交通事故,保障人身安全;提供安全合理的路线,避免交通拥堵;采用清洁无污染的电能作为汽车新能源,从而降低大气污染等。现如今,自动驾驶技术已经逐渐深入到各个领域并发挥着关键的作用。

qq_36130719的博客 3730

UNet改进(12):融合小波变换与注意力机制的图像分割新方法

本文提出了一种改进的WaveletAttentionUNet架构,通过结合小波变换和注意力机制来增强传统UNet的多尺度特征提取能力。该网络使用分组卷积模拟小波分解,将输入通道扩展为4个子带(LL、LH、HL、HH),并通过通道注意力机制自适应加权各子带特征。网络保留了UNet的编码器-解码器结构,在关键位置集成了WaveletAttention模块。实验证明该方法在医学图像分割等任务中能更好地保持边缘细节和复杂纹理特征,同时保持计算效率。

2501_91516851的博客 758

HashMap图文源码解析

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

echola_mendes的博客 834

全新YOLO26有效涨点改进专栏目录 | 本专栏持续更新500+篇内容 | 包含各种卷积、主干网络、各种注意力机制、检测头、损失函数、小目标检测改进、二次创新模块、独家创新等几百种创新点改进

🔥《2026年YOLO26改进专栏》🔥 🚀持续更新500+最前沿创新改进点(顶会顶刊论文/独家创新策略),涵盖主干网络、各种卷积、注意力机制、检测头等模块,助力科研论文发表与模型性能提升,支持检测/分割/分类任务。订阅即获完整可运行项目,提供专业QQ答疑群,适合科研发论文(SCI/CCF/核心)及工业应用(PCB/医学/遥感检测)。专栏价格将逐步上涨,早订更优惠! ⭐特色:非计算机专业友好、模块可自由组合、全网独家创新;📌适用:研究生大论文和小论文创新、小目标检测、多领域科研应用,满足不同研究需求。

Ai缝合怪、助力小伙伴高效发论文 5124

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

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

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

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

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

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

qq_43857727的博客 451

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

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

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

好好学java 2513

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的实现原理,进而又会问你能自己实现一个HashMap吗?在看jdk1.7的源码时,源码代码比较冗余,具体体现在key==null的处理 一下时具体的讲解 以下是HashMap的实现原理 创建一个HashMap,初始化容量,负载比例 然后对于put操作 1.刚开始put时候对于数组table是空的,所以样创建一个table的数组,...

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

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值