火影推荐程序连载49-记一次ElementUI源码修改过程

本文详细解读HashMap在JDK1.8之前的扩容原理,涉及resize()方法和transfer()核心操作,重点讲解数组长度翻倍、旧数据迁移策略和'头插法'的应用。

 最近在研究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是一个临时变量,用来引用或保存当前节点指向的下一节点,比如说当前节点  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://www.dongdongrji.cn maven.apache.org/xsd/maven-4.0.0.xsd">
  
  <artifactId>dubbo<www.xxinyoupt.cn /artifactId>
  
  <groupId>nacos</groupId>
  
  <version>0.0.1-SNAPSHOT<www.lanboyulezc.cn /version>
  
  <priority value=www.lanboylgw.com/"info"www.chuanchenpt.cn/ />
  
  <appender-ref ref=www.yixingxzc.cn"stdout"www.lanboylgw.com />
  
  <appender-ref ref="fileout"www.baichuangyule.cn /
  
  换掉encoder的实现类或者换掉layout的实现类就可以了
  
  <?xml version= www.lanboyulezc.cn www.jiuerylzc.cn"1.0"www.zhuyngyule.cn encoding=www.bhylzc.cn"UTF-8"?>
  
  <configuration debug=www.shicaiyulezc.cn"false"www.huachenguoj.com >
  
  <property name=www.51huayuzc.cn"APP_NAME" value="logtest"/>
  
  <property name=www.xinhuihpw.com "LOG_HOME" value="./logs" www.wanyaylezc.cn//>
  
  <appender name="STDOUT" class="www".yachengyl.cn"ch.qos.logback.core.ConsoleAppender">
  
  <!--替换成AspectLogbackEncoder-->
  
  <encoder class="www.shengrenyp.cn "com.yomahub.tlog.core.enhance.logback.AspectLogbackEncoder"www.51huayuzc.cn>
  
  <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{www.pinguo2yl.com} - %msg%n</pattern>
  
  <appender www.baishenjzc.cn name="FILE" www.baihua178.cn class="ch.qos.logback.core.rolling.RollingFileAppender">
  
  <File>${LOG_HOME}/${APP_www.jinliyld.cn NAME}.log<www.baihua178.cn /File>
  
  <rollingPolicy class="www.jintianxuesha.com"ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"www.wanyaylezc.cn/>
  
  <FileNamePattern>www.yachengyl.cn ${LOG_HOME}/${APP_NAME}.log.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
  
  <MaxHistory>30<www.51huayuzc.cn /MaxHistory>
  
  <maxFileSize>1000MB<www.jinliyld.cn /maxFileSize>
                            那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;             //把刚才保存的下一节点 作为下一轮循环的当前节点
            }
内容概要:本文档围绕水声网络(UAN)仿真中的信道建模展开,提供了基于Matlab的代码实现方案,旨在帮助科研人员构建和理解水声通信系统的仿真环境。文档不仅聚焦于信道建模的核心技术,还系统性地整合了智能优化算法、机器学习、图像处理、路径规划、无人机应用、信号处理、电力系统管理等多个前沿科研方向的技术方法与实际案例。涵盖的具体算法包括遗传算法、粒子群优化(PSO)、神经网络、卡尔曼滤波、支持向量机、极限学习机、卷积神经网络等,并深入探讨其在通信系统仿真中的应用。文档强调“借力”科研理念,倡导利用成熟的算法工具与仿真平台提升研究效率,并提供了丰富的配套资源,包括百度网盘链接和微信公众号入口,便于读者获取完整的代码、仿真模型及相关论文资料,全面支持科研复现与创新。; 适合人群:具备一定Matlab编程基础,从事通信工程、信号与信息处理、水声工程、自动化控制、电子信息、电力系统、无人机技术等相关领域的研究生、科研人员及工程技术人员。; 使用场景及目标:① 学习并复现水声网络信道建模的Matlab仿真流程;② 探索智能优化算法、机器学习、路径规划等技术在通信与多学科交叉系统仿真中的集成应用;③ 获取可用于科研项目的高质量算法代码、仿真案例与复现资源,加速课题研究进程,提升科研创新能力与论文发表水平。; 阅读建议:建议读者按照文档推荐的主题顺序逐步学习,优先聚焦自身研究方向的相关内容,并结合网盘提供的完整资源进行代码实践、仿真调试与结果验证,以实现理论理解与动手能力的双重提升,充分发挥本资源在科研攻关中的支撑作用。
代码下载链接: https://pan.quark.cn/s/b27638adc362 在工业自动化监控领域中,WinCC 被视为一种常用的可视化软件,其功能在于构建人机界面(HMI)以及SCADA系统。本资料将阐释在WinCC环境下如何构建一个展现管道中流体流动的动态效果,此功能主要通过C动作脚本来完成。在此过程中,我们需要构建两个矩形,分别标为 rec1 和 rec2。这两个矩形的高度相等,但 rec1 的宽度要小于 rec2。在具体实施时,rec1 将作为展示流体运动的可见单元,而 rec2 则作为辅助元素,尽管其“显示”属性被设为关闭,但在程序执行期间,其属性参数对流体动画的表现起着决定性作用,因为 rec2 与 rec1 的宽度差将决定流体每次移动的长度。 随后,我们需要将 rec1 和 rec2 整合为一个自定义对象。在自定义对象的属性配置中,应包含 rec1.Left、rec1.Width、rec1.Visible 和 rec2.Width 这些核心属性。这些属性将有助于在C脚本中精确控制对象的位置和可见状态,以达成流体运动的视觉效果。同时,用户可根据实际需求增加其他属性,以增强自定义对象的功能性。 在自定义对象的C脚本部分,我们设定了一个周期为“250ms”的触发器。该脚本的核心职责是计算并更新流体块的位置。借助 GetPropBOOL、GetPropWord 和 GetLeft 函数,我们可以获取对象的当前状态,涵盖其可见性、位置及宽度等参数。在循环操作中,流体块(rec1)将向右移动 rec2 - rec1 的距离,一旦流体块移出显示范围(即 rec1 的右边界达到或超过 rec2 的左边界),它将重新回到起始位置,从而形成流体持续流动的模...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值