ArrayList 基本介绍

ArrayList实现了List接口。它可以存储包括null的任何类型的对象,允许重复元素。ArrayList在内部使用一个数组来存储元素,当元素数量超过数组容量时,ArrayList会自动重新分配更大的内部数组,并且将现有元素复制到新数组中。ArrayList基本等同于Vector,但是ArrayList是线程不安全的(执行效率高),在多线程情况下不建议使用ArrayList

ArrayList 源码阅读及操作机制

首先ArrayList中用来存储元素的数组是 Object 类型的数组 elementData,ArrayList的容量就是这个数组的大小。

transient Object[] elementData;

通过 debug 下面这段代码来观察ArrayList的扩容机制。

public class TestArrayList() {
public static void main(String[] args) {
ArrayList list = new ArrayList();
// ArrayList list = new ArrayList(4);
for (int i = 1; i <= 10; i++) {
list.add(i);
}
for (int i = 11; i <= 15; i++) {
list.add(i);
}
}
}

构造方法

当使用无参构造器创建ArrayList对象时,会创建一个默认容量为10的空数组。

public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
// 用于默认大小的空实例的共享空数组。将其与 EMPTY_ELEMENTDATA 区分开,
// 以便在添加第一个元素时知道需要扩容多少。
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

使用指定大小的构造器创建ArrayList对象时,则初始 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);
}
}

add(E e)

add(E e)方法将指定元素添加到列表末尾,该方法先调用ensureCapacityInternal()方法确保容量至少是所需的最小容量(即当前大小加一),然后再赋值。

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

由于ArrayList允许的元素类型是 Object,所以添加基本类型的数据时,会先将其转换为对应的包装类型。

ensureCapacityInternal(int minCapacity)

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

calculateCapacity()

该方法计算需要的容量,如果elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA(使用无参构造器时即符合该条件),则返回DEFAULT_CAPACITY(10),否则返回 minCapacity(size + 1)。

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

ensureExplicitCapacity(int minCapacity)

modCount 记录列表被结构性修改的次数(结构性修改是指添加或删除一个或多个元素,或显式调整后备数组的大小,仅仅设置元素的值不是结构性修改)。如果需要的容量大于 elementData 的长度,则调用grow()方法进行扩容。

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

grow()

该方法增加容量以确保列表至少能够容纳最小容量参数minCapacity指定的元素数量。计算得到新容量应为旧容量的 1.5 倍。如果计算得到的新容量小于需要的最小容量,则新容量应为需要的最小容量(使用无参构造器第一次添加元素时即为这种情况,第一次扩容为 10)。如果请求的数组大小超过了虚拟机的限制,可能会导致 OutOfMemoryError。最后通过数组复制copyOf.copyOf()来进行真正的扩容。

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 = copyOf.copyOf(elementData, newCapacity);
}

总结

当使用无参构造器创建ArrayList对象时,elementData 初始容量为 0,第一次添加元素时 elementData 扩容为 10,以后再需要扩容,按 1.5 倍来扩容。若使用有参构造器创建ArrayList对象,elementData 初始容量为指定大小,如果需要扩容,则扩容为 1.5 倍。

值得注意的是,由于每次调整容量都需要将所有元素复制到新数组中,所以在元素数量较多时,频繁地调整容量可能会导致性能下降。为了避免频繁地调整容量,可以使用ArrayList的指定大小的构造方法或在添加大量元素之前使用ensureCapacity()方法预先指定较大的容量,以减少容量调整的次数。

另外,当从ArrayList中删除元素时,并不会立即缩小内部数组的容量。如果希望减少内存占用,可以使用trimToSize()方法来调整ArrayList的容量,使其与元素数量匹配。这样可以释放未使用的内存空间。

ArrayList 扩容机制的更多相关文章

  1. ArrayList扩容机制

    一.先从 ArrayList 的构造函数说起 ArrayList有三种方式来初始化,构造方法源码如下: 1 /** 2 * 默认初始容量大小 3 */ 4 private static final i ...

  2. ArrayList扩容机制以及底层实现

    简介 来源:博客园    作者:吾王彦 博客链接:https://www.cnblogs.com/qinjunlin/p/13724987.html ArrayList动态数组,是 java 中比较常 ...

  3. ArrayList扩容机制实探

    ArrayList初始化 问题:执行以下代码后,这个list的列表大小(size)和容量(capacity)分别是多大? List<String> list = new ArrayList ...

  4. 面试之arrayList扩容机制

    参考: ArrayList扩容详解_java编程艺术的博客-CSDN博客_arraylist扩容 ArrayList底层是数组elementData,用于存放插入的数据.初始大小是0,当有数据插入时, ...

  5. ArrayList源码解析(二)自动扩容机制与add操作

    本篇主要分析ArrayList的自动扩容机制,add和remove的相关方法. 作为一个list,add和remove操作自然是必须的. 前面说过,ArrayList底层是使用Object数组实现的. ...

  6. ArrayList的扩容机制

    一.ArrayList的扩容机制 1.扩容的计算方式是向右位移,即:newSize = this.size + (this.size>>1).向右位移,只有在当前值为偶数时,才是除以2:奇 ...

  7. 浅谈JAVA中HashMap、ArrayList、StringBuilder等的扩容机制

    JAVA中的部分需要扩容的内容总结如下:第一部分: HashMap<String, String> hmap=new HashMap<>(); HashSet<Strin ...

  8. 【数组】- ArrayList自动扩容机制

    不同的JDK版本的扩容机制可能有差异 实验环境:JDK1.8 扩容机制: 当向ArrayList中添加元素的时候,ArrayList如果要满足新元素的存储超过ArrayList存储新元素前的存储能力, ...

  9. 关于ArrayList的扩容机制

    关于ArrayList的扩容机制 ArrayList作为List接口常用的一个实现类,其底层数据接口由数组实现,可以保证O(1) 复杂度的随机查找, 在增删效率上不如LinkedList,但是在查询效 ...

  10. Java ArrayList自动扩容机制

    动态扩容 1.add(E e)方法中 ①  ensureCapacityInternal(size+1),确保内部容量,size是添加前数组内元素的数量 ②  elementData[size++] ...

随机推荐

  1. [软件设计&系统建模] Web软件通用能力模块

    0 基础工具 1 日志 2 权限 3 文件处理(下载/上传) 4 对象池 对象池 数据库连接池 线程池 5 微服务 服务网关 配置中心 注册中心 服务调用 服务熔断 健康检测 Actuator 6 缓 ...

  2. ModelAndView方法的返回值类型

    一.ModelAndView @RequestMapping("/selectById") public ModelAndView queryById(Integer id){ M ...

  3. 实时分布式低延迟OLAP数据库Apache Pinot探索实操

    @ 目录 概述 定义 特性 何时使用 部署 Local安装 快速启动 手动设置集群 Docker安装 快速启动 手动启动集群 Docker Compose 实操 批导入数据 流式导入数据 概述 定义 ...

  4. RDIFramework.NET WinForm版新增通知公告、系统新闻模块

    1.系统新闻功能描述 系统新闻模块,用户可以根据实际情况做相应应用,如用在内部业务系统的展示中或网站上新闻的展示.新闻可以分类进行管理,非常的实用.系统新闻管理主要分为添加.修改.删除与移动系统新闻. ...

  5. AI人工智能简史

    AI人工智能简史 最近学习AI,顺便整理了一份AI人工智能简史,大家参考: 1951年 第一台神经网络机,称为SNARC: 1956年 达特茅斯学院会议,正式确立了人工智能的研究领域: 1966年 M ...

  6. 设置Windows主机的浏览器为wls2的默认浏览器

    这里以Chrome为例. 1. 准备工作 wsl是可以使用Windows主机上安装的exe程序,出于安全考虑,默认情况下改功能是无法使用.要使用的话,终端需要以管理员权限启动. 我这里以Windows ...

  7. 微服务为什么要用到 API 网关?

    本文介绍了 API 网关日志的价值,并以知名网关 Apache APISIX 为例,展示如何集成 API 网关日志. 作者程小兰,API7.ai 技术工程师,Apache APISIX Contrib ...

  8. 基于 Github 平台的 .NET 开源项目模板. 嘎嘎实用!

    简介 大家好,为了使开源项目的维护和管理更方便一些,出于个人需求写了一款开源项目的模板,该模板基于 Github 平台,并使用 .NET 来实现管道功能. 在接受过实战检验后, 于今天开源, 项目地址 ...

  9. C# 打开蓝牙设置界面

    蓝牙设置相关界面,以下是通过C#方式打开的几个方式,记录一下 蓝牙设置界面 1.控制面板命令bthprops.cpl 可以用控制面板 control+bthprops.cpl,也可以直接bthprop ...

  10. Vite-WeGPT聊天AI实例|vue3+pinia仿ChatGPT聊天界面

    基于vue3.x+vite4+pinia2仿chatgpt聊天模拟实例Vue3-WeGPT. 基于Vite4.x+Vue3+Pinia2+VEPlus+Vue3-Markdown等技术实现仿ChatG ...