当前位置: 首页 > news >正文

JDK1.8源码 resize()解析

final HashMap.Node<K,V>[] resize() {
        HashMap.Node<K,V>[] oldTab = table;
        int oldCap = (oldTab == null) ? 0 : oldTab.length;
        int oldThr = threshold;	//threshold在table未初始化时存储的是构造方法中tableSizeFor(initialCapacity)的值,如果未带参数initialCapacity,则是0;**tableSizeFor()方法不懂可以看之前的博客**
        int newCap, newThr = 0;
        if (oldCap > 0) {		//HashMap中添加过元素的情况下oldCap才会大于0,否则未初始化oldTab==null,oldCap==0;
            if (oldCap >= MAXIMUM_CAPACITY) {	//原来的容量大于等于HashMap最大容量,给临界值赋值为一个四位整型的最大值,大约为MAXIMUM_CAPACITY的两倍(MAXIMUM_CAPACITY=2^30=1073741824,Integer.MAX_VALUE=2147483647)
                threshold = Integer.MAX_VALUE;
                return oldTab;
                //这段代码整体意思就是  因为添加过元素之后,临界值是容量的0.75倍,达到这个值就会扩容,因为容量已经达到最大,所以给临界值设置一个达不到的值,为的就是以后再进行添加元素时,不会再扩容;
            }
            else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
             oldCap >= DEFAULT_INITIAL_CAPACITY)	//添加过元素的扩容,直接容量和临界值扩大两倍
                newThr = oldThr << 1; // double threshold
        }
        else if (oldThr > 0) // initial capacity was placed in threshold
            newCap = oldThr;	//未添加元素的时,进行初始化,因为oldThr=threshold存储的是构造方法中tableSizeFor(initialCapacity)的值,所以这里newCap得到的值是初始化容量大小
        else {               // zero initial threshold signifies using defaults
            newCap = DEFAULT_INITIAL_CAPACITY;
            newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
            //未调用initialCapacity的有参构造方法,进行默认大小赋值
        }
        if (newThr == 0) {	//当上述代码执行第二个条件语句时,newThr未进行赋值,所以在这里赋值;
            float ft = (float)newCap * loadFactor;
            newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
             (int)ft : Integer.MAX_VALUE);
             //其实就是容量newCap的0.75倍
        }
        threshold = newThr;//重新给临界值赋值,第一次调用resize()过后都不在存储初始容量
        @SuppressWarnings({"rawtypes","unchecked"})
        HashMap.Node<K,V>[] newTab = (HashMap.Node<K,V>[])new HashMap.Node[newCap];
        table = newTab;
        if (oldTab != null) {	//把oldTab上的元素移动到newTab上
            for (int j = 0; j < oldCap; ++j) {
                HashMap.Node<K,V> e;
                if ((e = oldTab[j]) != null) {//遍历oldTab
                    oldTab[j] = null;
                    if (e.next == null)//如果oldTab[j]上只存在一个节点,直接挂到newTab上
                        newTab[e.hash & (newCap - 1)] = e;//[e.hash & (newCap - 1)]计算下标,不懂可参考之前的博客
                    else if (e instanceof TreeNode)//如果是树节点,则进行树处理,有点复杂,不展开多讲,有兴趣自己去了解。嘻嘻~
                        ((HashMap.TreeNode<K,V>)e).split(this, newTab, j, oldCap);
                    else { // preserve order	这里是对oldTab[j]存在不止一个节点时,进行处理
                        HashMap.Node<K,V> loHead = null, loTail = null;//这两个节点是维护一个位置未发生变化的链表(维护oldTab[j]下位置不变的节点)
                        HashMap.Node<K,V> hiHead = null, hiTail = null;//这两个节点是维护一个位置发生变化的链表(维护oldTab[j]下位置变化的节点)
                        //因为原来的元素位置可能保持不变,可能是原来位置加上原来的oldTab长度:
                        //hash(不变情况):	 0000 0000 0000 0010	
                        //oldCap(16)-1:    	 0000 0000 0000 1111
                        //newCap(32)-1:      0000 0000 0001 1111
                        //hash(变化情况):	 0000 0000 0001 0010
                        //按位与运算,我们可以明显的看出,不变情况的两种计算的结果是[2],而位置变化情况两种计算结果分别是[2],[18];	
                        HashMap.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;//直接把维护位置不变的链表头结点挂在newTab[j]上
                        }
                        if (hiTail != null) {
                            hiTail.next = null;
                            newTab[j + oldCap] = hiHead;//直接把维护位置变化的链表头结点挂在newTab[j + oldCap]上
                        }
                    }
                }
            }
        }
        return newTab;
    }

啃源码不易,有收获的小伙伴点个赞哦~

相关文章:

  • HashMap中的迭代器
  • Hashtable中的get(key)方法,为什么进行hash 0x7FFFFFFF
  • Hashtable中的rehash()方法
  • mysql查询一个时间段的数据
  • Linux中的shell是什么
  • JUC笔记
  • 共享模型之管程
  • 共享模型之内存
  • 共享模型之无锁
  • 全面解析ThreadLocal
  • BIO-NIO-AIO笔记
  • docker 运行出错 Error response from daemon: error creating overlay mount to /var/lib/docker/overlay2/007
  • JAVA多态
  • 状态压缩DP--------蒙德里安的梦想
  • 区间DP————石子合并
  • Apache的80端口被占用以及访问时报错403
  • golang 发送GET和POST示例
  • JS+CSS实现数字滚动
  • Mac 鼠须管 Rime 输入法 安装五笔输入法 教程
  • Meteor的表单提交:Form
  • MobX
  • Mocha测试初探
  • mysql外键的使用
  • PHP那些事儿
  • Python学习笔记 字符串拼接
  • spring-boot List转Page
  • vue2.0一起在懵逼的海洋里越陷越深(四)
  • 第十八天-企业应用架构模式-基本模式
  • 试着探索高并发下的系统架构面貌
  • 微信公众号开发小记——5.python微信红包
  • 以太坊客户端Geth命令参数详解
  • const的用法,特别是用在函数前面与后面的区别
  • #单片机(TB6600驱动42步进电机)
  • #我与Java虚拟机的故事#连载08:书读百遍其义自见
  • #周末课堂# 【Linux + JVM + Mysql高级性能优化班】(火热报名中~~~)
  • %3cli%3e连接html页面,html+canvas实现屏幕截取
  • (2)MFC+openGL单文档框架glFrame
  • (Redis使用系列) Springboot 实现Redis消息的订阅与分布 四
  • (第9篇)大数据的的超级应用——数据挖掘-推荐系统
  • (定时器/计数器)中断系统(详解与使用)
  • (附源码)apringboot计算机专业大学生就业指南 毕业设计061355
  • (源码版)2024美国大学生数学建模E题财产保险的可持续模型详解思路+具体代码季节性时序预测SARIMA天气预测建模
  • (转)fock函数详解
  • (转)linux 命令大全
  • (转)一些感悟
  • .NET 实现 NTFS 文件系统的硬链接 mklink /J(Junction)
  • .NET国产化改造探索(三)、银河麒麟安装.NET 8环境
  • /var/spool/postfix/maildrop 下有大量文件
  • @ 代码随想录算法训练营第8周(C语言)|Day53(动态规划)
  • @EventListener注解使用说明
  • [ 渗透工具篇 ] 一篇文章让你掌握神奇的shuize -- 信息收集自动化工具
  • [⑧ADRV902x]: Digital Pre-Distortion (DPD)学习笔记
  • [AutoSAR系列] 1.3 AutoSar 架构
  • [echarts] y轴不显示0
  • [HackMyVM]靶场Boxing