ArrayList扩容机制

简介: 本文深入分析了ArrayList的add及扩容机制。添加首个元素时触发ensureCapacityInternal,初始容量为10;当元素数超过当前容量时,调用grow方法将容量扩充至原1.5倍,通过位运算提升性能,并结合minCapacity与MAX_ARRAY_SIZE处理边界情况,确保集合高效稳定扩展。

先来看Add方法

再来看看ensureCapacityInternal()方法,可以看到add()方法首先调用了ensureCapacityInternal(size+1)
当要add进第一个元素时,minCapacity为1,在Math.max()方法比较后,minCapacity为10
ensureExplicitCapacity()方法

Java

运行代码复制代码

1

2

3

4

5

6

7

8

//判断是否需要扩容

private void ensureExplicitCapacity(int minCapacity) {

modCount++;

// overflow-conscious code

if (minCapacity - elementData.length > 0)

//调用grow()方法进行扩容,调用此方法代表已经开始扩容了

grow(minCapacity);

}

我们来仔细分析一下
1当我们要add进第一个元素到ArrayList时,elementData.length为0(因为还是一个空的list,里面还没有数据,所以没有进行扩容,默认扩容10),因为执行了ensureCapacityInternal()方法,所以minCapacity此时为10。此时,minCapacity - elemetData.length > 0(minCapacity=10,elemetData.length=0)成立,所以会进入==grow(minCapacity)==方法。
2当add第2个元素时,minCapacity为2,此时elementData.length(容量)在添加第一个元素后扩容成10了。此时,minCapacity - elementData.length > 0不成立,所以不会进入(执行)==grow(minCapacity)==方法。
3添加第3、4…到第10个元素时,依然不会执行==grow()==方法,数组容量都为10。知道添加第11个元素,minCapacity(为11)比elementData.length(为10)要大。进行grow方法进行扩容
4grow方法

Java

运行代码复制代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

private void grow(int minCapacity) {

// oldCapacity为旧容量,newCapacity为新容量

int oldCapacity = elementData.length;//(0,10,15)

//将oldCapacity右移一位,其效果相当于oldCapacity/2;

// 我们知道位运算的速度远远快于整除运算,整句运算式的结果就是将新容量更新为旧容量的1.5倍

int newCapacity = oldCapacity + (oldCapacity >> 1);

// 然后检查新容量是否大于最小需要容量,若还是小于最小需要容量,那么久把最小需要容量当作数组的新容量

if (newCapacity - minCapacity < 0)

newCapacity = minCapacity;

//判断新容量是否大于集合的最大容量(一般大不了)

if (newCapacity - MAX_ARRAY_SIZE > 0)

newCapacity = hugeCapacity(minCapacity);

// 给elementData从新赋值(10,15)

elementData = Arrays.copyOf(elementData, newCapacity);

}

int newCapacity = oldCapacity + (oldCapacity >> 1),所以 ArrayList 每次扩容之后容量都会变为原来的 1.5 倍!
“>>”(移位运算符):>>1 右移一位相当于除2,右移n位相当于除以 2 的 n 次方。这里 oldCapacity 明显右移了1位所以相当于oldCapacity /2。对于大数据的2进制运算,位移运算符比那些普通运算符的运算要快很多,因为程序仅仅移动一下而已,不去计算,这样提高了效率,节省了资源
通过例子探究一下grow()方法
当add第一个元素时,oldCapacity为0,经比较后第一个if判断成立,newCapacity = minCapacity(为10)。但是第二个if判断不会成立,即newCapacity不比MAX_ARRAY_SIZE大,则不会进入hugeCapacity方法。数组容量为10,add方法中return true,size增为1。
当add第11个元素进入grow方法时,newCapacity为15,比minCapacity(为11)大,第一个if判断不成立。新容量没有大于数组最大size,不会进入hugeCapacity方法。数组容量扩为15,add方法中rerurn,true,size增为11。
以此类推…这里补充一点比较重要,但是容易被忽视掉的知识点:
java中的length属性是针对数组说的,比如说你声明了一个数组,想知道这个数组的长度则用到了length这个属性。
java中的length() 方法是针对字符串说的,如果想看这个字符串的长度则用到 length() 这个方法。
java中的size() 方法是针对泛型集合说的,如果想看这个泛型有多少元素,就调用此方法类查看!


相关文章
|
人工智能 文字识别
文字识别OCR提示这个报错 ,怎么解决?Timeout on reading data from socket
文字识别OCR提示这个报错 ,怎么解决?Timeout on reading data from socket
484 1
|
机器学习/深度学习 资源调度 程序员
PMP考试计算题专题
PMP考试计算题专题
437 0
|
传感器 算法 物联网
《移动互联网技术》第三章 无线定位技术:掌握位置服务和室内定位的基本概念和工作原理
《移动互联网技术》第三章 无线定位技术:掌握位置服务和室内定位的基本概念和工作原理
642 0
|
JavaScript 数据安全/隐私保护
Discuz! X3.5 注册页面提示语的修改方法
Discuz! X3.5 注册页面提示语的修改方法
707 2
|
Oracle 关系型数据库 Linux
VMware的创始人
VMware的创始人
364 4
|
数据采集 机器学习/深度学习
港大发布智能交通大模型全家桶OpenCity!打破时空零样本预测壁垒,训练速度最多提升50倍
【10月更文挑战第15天】香港大学近日发布了智能交通大模型OpenCity,旨在通过创新技术手段解决城市交通预测和管理难题。OpenCity结合了Transformer和图神经网络(GNN)的优势,能够有效捕捉复杂时空依赖关系,实现零样本预测。该模型采用大规模异构交通数据集预训练,显著提升了泛化能力和训练速度,实验结果显示其在未见过的城市或区域的交通预测中表现出色。然而,模型的计算资源需求和数据质量仍需进一步优化。
273 1
|
存储 数据可视化 前端开发
基于python的当当二手书数据分析与可视化系统设计与实现
本文设计并实现了一个基于Python的当当二手书数据分析与可视化系统,通过数据收集、清洗、聚类分析和可视化展示,为二手书市场提供全面的数据分析和决策支持,以促进资源循环利用和市场效率优化。
634 0
基于python的当当二手书数据分析与可视化系统设计与实现
|
运维 监控 安全
构建高效自动化运维系统:DevOps在企业级应用的实现路径
【7月更文挑战第54天】在当今IT领域,DevOps作为一种文化和实践,旨在弥合开发与运维之间的鸿沟,以实现更快速、更可靠的产品交付。本文将深入探讨在企业环境中如何构建一个高效的自动化运维系统,不仅涵盖理论框架,还包括具体实施步骤和最佳实践。通过持续集成(CI)、持续部署(CD)、基础设施即代码(IaC)等关键概念的融合运用,文章旨在为读者提供一个清晰的指导,以便在其组织中落实DevOps策略,并实现运维效率的显著提升。
|
安全 算法 Java
【Java集合类面试二】、 Java中的容器,线程安全和线程不安全的分别有哪些?
这篇文章讨论了Java集合类的线程安全性,列举了线程不安全的集合类(如HashSet、ArrayList、HashMap)和线程安全的集合类(如Vector、Hashtable),同时介绍了Java 5之后提供的java.util.concurrent包中的高效并发集合类,如ConcurrentHashMap和CopyOnWriteArrayList。
【Java集合类面试二】、 Java中的容器,线程安全和线程不安全的分别有哪些?
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的中医学习服务管理系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的中医学习服务管理系统的详细设计和实现(源码+lw+部署文档+讲解等)
262 0