【Java】JDK 1.8 ArrayList扩容原理

Python+Appium实现泛微OA自动打卡:5分钟搭建移动端自动化脚本 移动端自动化测试是软件测试与办公自动化领域的重要技术方向,其核心原理是通过程序模拟用户对手机应用界面的操作,实现重复性任务的自动执行。Appium作为主流的开源移动端自动化框架,基于WebDriver协议,支持跨平台且无需修改被测应用,为自动化脚本开发提供了标准化接口。在工程实践中,结合Python简洁的语法和丰富的生态,可以快速构建稳定可靠的自动化解决方案。这一技术组合的价值在于能够高效处理“重复性、低价值、高频率”的日常操作,例如考勤打卡、数据填报等办公场景,显著提升工作效率。本文以泛微OA Emobi 阅读详情

两个构造器

ArrayList的以下属性,跟扩容有关。

//无参构造时,初始容量大小
private static final int DEFAULT_CAPACITY = 10;
//存放ArrayList元素的数组
transient Object[] elementData;
//ArrayList的大小
private int size;
//传参为0时构造的数组
private static final Object[] EMPTY_ELEMENTDATA = {};
//无参构造时的“空”数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

ArrayList一共有三个构造器,这里主要提到前两个,即无参的和传入一个整数的构造器。

public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

无参的很简单,直接将DEFAULTCAPACITY_EMPTY_ELEMENTDATA赋给元素数组。

public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
    }
}

有参的也很简单,传入的参数大于0时,创建一个新的Object数组。等于0时,将EMPTY_ELEMENTDATA赋给元素数组,小于0时,直接抛异常。

这两种方式创建的ArrayList在扩容的时候,会有细微的区别。

以下源码基于JDK 1.8。

使用无参构造器的扩容机制

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

执行add方法,首先会调用ensureCapacityInteral(int minCapacity)方法。

private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

这个方法的参数是minCapacity,最小容量,此时minCapacity=size+1=0+1=1。这个方法又会调用ensureExplicitCapacity(int minCapactiy)方法。在这之前会调用calculateCapacity(elementData, minCapacity)方法,利用其返回值。

private static int calculateCapacity(Object[] elementData, int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
}

这个方法,传入的参数是elementData和minCapactiy,如果数组是由无参构造器建造的,那么就返回默认数组大小DEFAULT_CAPACITY和当前最小容量minCapacity的较大值。此时minCapacity=1,默认为10,所以返回的是10。

所以,当由无参构造器构造时,如果minCapacity<10,就返回10;大于10,则返回minCapacity,也就是当前容量+1(即size+1)。

而有参构造器构成时,总是返回minCapacity,也即(size+1)。

那么此时ensureExplicitCapacity方法的入参,就是10,

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
    	grow(minCapacity);
}

由于执行了添加操作,所以modCount++(这个参数在迭代器的hasNext()和next()会用到,可能会抛出ConcurrentModificationException),接着判断minCapacity和当前数组长度的关系,此时minCapacity=10,数组长度为0,minCapacity-element.length>0,所以要执行grow(int minCapacity)方法,对数组进行扩容。

private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
}

oldCapacity=0,newCapacity=oldCapacity*1.5还是=0,所以newCapacity-minCapacity=0-1<0,把newCapacity设置为minCapacity,然后调用Arrays.copyOf方法,将原数组扩容至newCapacity,也就是10。

最后通过elementData[size++] = e,完成添加,此时size=1。


第2次(一直到第10次)添加的时候,还是先调用ensureCapacityInteral(size+1),此时传入的参数为2。

然后调用calculateCapacity(elementData, minCapacity=2),2<默认值10,还是返回10。

在ensureExplicitCapacity中,由于此时数组的容量是10,而10-10=0,所以不执行grow方法。

那么直接就是elementData[size++] = e,size=2。


第11次添加的时候,依然调用ensureCapacityInteral(size+1),此时传入的参数是11。

然后调用calculateCapacity(elementData, minCapacity=11),11>默认值10,返回11。

在ensureExplicitCapacity中,由于此时数组的容量是10,而11-10>0,所以又要进行扩容了。

grow方法,此时传入的参数是11,oldCapacity是10,newCapacity是15,newCapacity-minCapacity=4>0,直接复制数组,长度由10增加到15,最后完成添加。

此后以此类推。


使用有参构造器的扩容机制

如果是有参构造的,那么elementData=EMPTY_ELEMENTDATA,add的时候,依然会先调用ensureCapacityInteral(size+1),传入的参数是1。

在calculateCapacity中,此时elementData并不等于DEFAULTCAPACITY_EMPTY_ELEMENTDATA,条件不成立,所以直接返回minCapacity也就是1。

那么ensureExplicitCapacity的入参,就是1,此时1-length=1>0,所以执行grow方法。

grow方法中,旧容量为0,新容量还是为0,newCapacity-minCapacity<0,触发newCapacity=minCapacity,新容量=1,然后进行数组复制,添加成功。


第2次添加的时候,ensureCapacityInteral(size+1),传入的是2。

calculateCapacity始终返回minCapacity,所以是2。

ensureExplicitCapacity的入参,是2,2-1>0,又要执行grow方法。

grow方法中,旧容量为1,新容量为1,此时1-1=0,1-2<0,新容量=2,然后添加。

之后的每一次添加,传入的minCapacity都会大于elementData.length,所以每次添加都要执行grow。


区别

总的来说:

使用无参构造的ArrayList,在第一次添加后,会直接把容量扩容至10,接下来的2~10次添加,数组都不会扩容。之后一旦容量不够,就会扩容至原来的1.5倍。

而使用有参(initalCapacity=0)构造的ArrayList,每一次添加,都会进行扩容。

这么看来,当ArrayList存储的元素数量小于等于10时,无参构造的ArrayList性能要比有参构造的稍微高那么一点点,毕竟少了复制数组的操作。

Natural Language Processing 作者:禅与计算机程序设计艺术 1.简介 自然语言处理(NLP)是研究如何使计算机理解和处理自然语言的理论和方法,目的是让电脑更好的理解、获取、生成、存储和沟通人类语言。20世纪80年代末,IBM的三位博士陈天奇、周博磊和王力雄在贝尔实验室创建了首个自然语言处理系统——“布莱克多·艾森豪威尔”(Bletc 阅读详情

相关推荐

利用Spm12进行fMRI数据分析:从预处理到结果解读的完整指南

本文提供了利用SPM12进行fMRI数据分析的完整流程指南,涵盖从数据预处理、统计建模到结果解读的全过程。详细介绍了在MATLAB环境下使用SPM12图形界面完成头动矫正、空间标准化等关键步骤的操作方法与避坑技巧,帮助神经科学研究者和心理学研究者高效处理功能磁共振成像数据并产出可靠结果。

weixin_29079671的博客 452

ArrayList 的扩容机制

创建用户自定义长度的数组ArrayList扩容的核心从ensureCapacityInternal方法说起。可以看到前面介绍成员变量的提到的ArrayList有两个默认的空数组:**DEFAULTCAPACITY_EMPTY_ELEMENTDATA:**是用来使用默认构造方法时候返回的空数组。如果第一次添加数据的话那么数组扩容长度为DEFAULT_CAPACITY=10。

Afu1021的博客 339

使用 VPN 访问太理内部网相关问题总结【太原理工大学】

电脑连接 VPN,访问校园内部网相关问题总结,太原理工大学。

m0_52861684的博客 9878

JDK1.8中ArrayList的扩容机制理解

Arraylist的扩容机制发生在add()方法运行时: public boolean add(E e) { //扩容 ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } 首先ensureCapacityInternal(size+1)方法对添加元素后数组大小进行判断: pr

u014713873的博客 748

Kettle实战:如何用JavaScript脚本实现数据库表批量操作(附完整代码)

本文详细介绍了如何利用Kettle的JavaScript脚本实现数据库表批量操作,包括表名采集、循环遍历和动态SQL生成等关键步骤。通过实战案例和完整代码示例,帮助ETL工程师高效处理数据密集型任务,提升数据库操作的自动化水平。

weixin_29019241的博客 231

CEEMDAN算法及其应用

本博文主要介绍CEEMDAN算法的原理及其在信号去噪方面的应用

总结论文中的算法并给出论文的复现代码 6万+

八股文之浅谈ArrayList扩容机制篇(jdk1.8)

本文主要介绍ArrayList的扩容机制,详细说明底层在什么时候实现扩容的、是如何实现扩容的

weixin_59216829的博客 1914

面试官连夜整理:103道AI Agent面试题,答对一半直接加薪50%

维度AutoGPTLangGraphAutoGen控制流LLM 驱动的隐式循环代码层定义的显式状态图对话驱动的自动流转状态存储Prompt 上下文中(易丢失)结构化 State 对象(可持久化)对话历史(自动累积)分支能力依赖 LLM 的文本输出(不稳定)条件边 + 节点路由(确定性)多 Agent 对话自然分支(涌现式)回溯/回滚无原生支持,只能重新开始原生 Checkpoint 支持时间旅行无全局回滚,单 Agent 可重启人机协同仅人工在关键点介入(需要自定义)原生支持。

weixin_35774598的博客 622

arraylist扩容机制(源码解读)JDK1.8

ArrayList ArrayList的底层是通过一个数组这种数据结构来存储数据的, 见源码 //底层实现所用到的东西,就是这个数组 transient Object[] elementData; 我们知道,JAVA中数组的长度大小是固定的,因此每次扩容,实际上是新申请一个长度更大的数组,并把原来数组中的内容拷贝进去,以此来达到扩容的目的。 那么我们来看看他这种扩容机制是按照什么原理。 同时我们来先看看源码中都有哪些成员变量 //serialVersionUID适用于java序列化

hdjcp的博客 336

LAMMPS-使用MATLAB计算径向分布函数

首先需要使用LAMMPS进行分子动力学模拟,并获取到所需的数据文件,LAMMPS是一款开源的分子动力学模拟软件,可以模拟原子、分子和离子的运动行为,对于本文的目标假设你已经完成了LAMMPS的安装和模拟过程,获得了数据文件。)是一种重要的统计工具,用于描述原子或分子之间的空间分布情况,通过计算RDF可以获得物质的结构信息、相互作用距离以及相位转变等重要参数,本文将介绍如何使用MATLAB计算LAMMPS生成的数据文件的径向分布函数。变量替换为你的实际数据文件的名称。

weixin_50547796的博客 515

第42篇FEDGLOSS算法BEYOND LOCAL SHARPNESS:COMMUNICATION-EFFICIENT GLOBALSHARPNESS-AWARE MINIMIZATIONFOR

:用上一轮伪梯度最小化锐度,获取与全局损失最相关的几何信息,引导全局优化趋向更平坦的最小值。效果对比分析:FEDGLOss。

weixin_74009895的博客 526

Java ArrayList扩容机制(基于JDK1.8)

ArrayList继承自AbstractList,实现List接口,是一个可变长的列表。 不同于LinkedList,LinkedList底层由链表实现,所以只需维护好底层链表,即可实现列表的长度变化。而ArrayList底层由数组实现,数组初始化需要指定长度,所以想要实现可变长的列表,ArrayList底层肯定做了一些小动作来支持。今天看了下ArrayList的源码,记录一下它的扩容机制。 首先,需要了解类内的这6个属性: /** * 列表默认的初始化容量,10 */

Welcome to tiny_spot 668

ArcGIS Pro 3.4 二次开发 - 布局

本文介绍了在ArcGIS Pro SDK 3.4和.NET 8环境下操作布局工程项的相关方法。主要内容包括:引用布局工程项和关联布局,在新视图中打开或激活已有布局视图,引用活动布局视图,导入/移除布局工程项,创建基本布局或带参考线的自定义布局,修改布局页面尺寸,以及创建圆形图形元素等操作。重点演示了如何通过CIM(Core Infrastructure Model)进行高级布局配置,并详细说明了圆形图形元素的创建过程,包括几何构建、符号设置和图形生成。所有涉及UI线程的操作都遵循ArcGIS Pro SDK

Winemonk 795

Java集合之ArrayList源码详解

ArrayList源码解析以及相关面试题总结。

个人博客,欢迎收藏。 1066

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

java集合

HashMap中,如果key经过hash算法得出的数组索引位置全部不相同,即Hash算法非常好,那样的话,getKey方法的时间复杂度就是O(1),如果Hash算法技术的结果碰撞非常多,假如Hash算极其差,所有的Hash算法结果得出的索引位置一样,那样所有的键值对都集中到一个桶中,或者在一个链表中,或者在一个红黑树中,时间复杂度分别为O(n)和O(lgn)。当然Java里的数组是无法自动扩容的,方法是使用一个新的数组代替已有的容量小的数组,就像我们用一个小桶装水,如果想装更多的水,就得换大水桶。

weixin_72525373的博客 1012

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

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

Java集合篇:ArrayList(源码分析,实现原理,扩容机制),散列表(哈希冲突,拉链法),HashMap(实现原理,jdk1.7和jdk1.8区别,put方法,扩容机制,寻址算法,多线程死循环)

①散列表(Hash Table)又名哈希表/Hash表②根据键(Key)直接访问在内存存储位置值(Value)的数据结构③由数组演化而来的,利用了数组支持按照下标进行随机访问数据。

jungleirim的博客 1703

IMSL CNL 7.0.0 (x86-64)Crack

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

java元空间扩容_深入理解ArrayList的扩容机制的原理

前言:在面试中我们经常被问到说ArrayList和数组有什么不同,但我认为我们有必要去深入了解下ArrayList的原理。我们在日常开发的过程中,ArrayList也是经常使用的,接下来和小编一起淡来学习下ArrayList原理吧。下面的代码是基于JDK1.8的// 默认为 0private int size;/*** Appends the specified element to the en...

weixin_42501949的博客 285

JDK1.8源码阅读之java.util.ArrayList

JDK1.8源码阅读之java.util.ArrayList 构造器方法 无参构造器 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; transient Object[] elementData; // non-private to simplify nested class access // 将elementData数组初始化为空。 // 这里是惰性扩容,当要往数组中插入元素时,才会初始化扩容成默认长度10。

striver 13 227

HashMap,ArraryList底层原理-java基础day01

本文介绍了hashmap和arraylist的基本原理

weixin_54949457的博客 482

大厂java面试题——集合篇(1)

💴哈喽,大家好丫,你们的小郭子又来啦 ~ 今天我们来聊一聊java面试中的【集合问题】

weixin_51331210的博客 575

Java常用底层数据结构设计思想-集合类-从ArrayList到HashMap

数据结构决定实现:ArrayList的数组拷贝、HashMap的2的幂约束,均是对底层数据结构特性的深度适配;轻量级设计优先:通过引用标记、默认值等轻量级方式区分场景,而非额外成员变量,实现代码高内聚;按需分配资源:延迟初始化、增量扩容,最大化减少内存浪费,兼顾性能与资源利用率;迭代优化思维:JDK7到JDK8的优化(ArrayList双空数组、HashMap尾插法),体现了“发现问题-优化状态标记-统一逻辑”的迭代思路。

Coder_Boy_的博客 796

ArratsList实现原理(面试必背)

ArrayList底层原理

xiashaoqi的博客 512

Java应届生求职八股(4)---集合篇

这句代码中,是函数,list进行。

weixin_58493933的博客 889

集合源码学习--ArrayList

属性: private static final int DEFAULT_CAPACITY = 10; private static final Object[] EMPTY_ELEMENTDATA = {}; private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; transient Object[] eleme...

weixin_44774355的博客 180

【Java拾遗】JDK源码之集合篇

说明 这里文章大多为复习内容,内容精简干练,为原有基础知识回顾 ArrayList,LinkedList 使用到的工具类 System.arraycopy(srcElements, srcIndex, targetElement, tarIndex, srcLength);Arrays.copyOf(数组,型数组长度); 位运算复习 x>>1 等价于: x / 2 (2...

一枝花算不算浪漫的专栏 354

ArrayList面试八问,你都会了吗

背景: 我们经常会在网上看到一些面试题,比如HashMap数据结构、Handler实现原理、binder进程通信等等。但是很多文章都是深入分析,缺少对每个环节问题点提问,比如这块为什么要这么设计。面试官也不会问完一个问题就结束,也会逮着追问,直到问到你不会。特别是大厂都喜欢一步步深入提问,来考察你对知识点掌握的深度。 本文计划从ArrayList切入,尽可能覆盖面试过程中涉及ArrayList的所有问题点。问题和解答尽量精简易懂,每个人视角不一样,如果大家有遇到文章中没有提到的问题点,可以留言或私信指出。

tenderhearted的专栏 1064
上一篇: 【Java】值传递和引用传递
csdn_inside
博客等级 码龄10年 52粉丝 33原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值