Java-基础-ArrayList
1. 简介
ArrayList 实现了 List 接口,其底层基于数组实现容量大小动态可变。既然是数组,那么元素存放一定是有序的,并允许包括 null 在内的所有元素。
每个 ArrayList 实例都有一个容量(capacity)。该容量是指用来存储列表元素的数组的大小。它总是至少等于列表的大小。随着向 ArrayList 中不断添加元素,其容量也自动增长。
2. 初始化
ArrayList 初始化源码如下:
看了源码之后感觉ArrayList的初始化好简单,有如下几种方式:
- 构造一个空数组。
- 构造一个指定长度的数组。
- 将传入的集合转成数组,并指向 elementData。
既然创建ArrayList实例是通过new出来的,那我们不妨看一看list1实例在jvm中是如何分布的。
ArrayList.class 被加载时,static修饰的变量,会被加载到方法区。
当我们再创建一个ArrayList实例list2,会是如何分布呢?
通过数据在JVM中的分布,我们可以了解到作者设计的巧妙之处,当我们创建多个list实例时,其实底层都是指向缓存在方法区的Object[]数组。
3. 自动扩容
3.1 第一次添加元素
在看自动扩容之前,我们先了解下当我们第一次给list中添加元素的时候,底层都干了些什么事。
我们继续看下ensureCapacityInternal
方法。
copy过程如下:
从源码中得知,当我们创建一个空的list,并且第一次给list中添加元素的时候:
- 创建一个长度为
DEFAULT_CAPACITY = 10
的数组 - 将
elementData
中的值copy到新数组中(当然,这时的elementData为空) - 将初始化好的新数组赋值给
elementData
3.2 如何扩容
当我们了解了arrayList第一次添加元素的逻辑后,我们也基本明白了动态扩容
的原理,其实就是创建一个新的数组覆盖之前的数组,如图:
但是有两个问题:
- 何时扩容?
- 扩多大?
我们带着疑问再去看下源码:
看到这里,心中的疑惑就解开了:
- 当ArrayList内部的elementData[]没有空闲位置时,才进行扩容。
- 每次将之前的size扩容1.5倍。
4. 插入元素
我们在前面了解了arrayList是如何添加元素的,都是给尾部追加元素,但是如果给指定位置添加元素是如何实现的呢?
我们先通过源码分析一下:
是不是看完源码后对System.arraycopy()
还是有点懵。我们在着重看下这个方法
我这里写了个list插入和数组执行过程的demo方便大家加深理解:
5. 移除元素
remove()
方法也有两个版本,一个是remove(int index)
删除指定位置的元素,另一个是remove(Object o)
删除第一个满足o.equals(elementData[index])
的元素。删除操作是add()
操作的逆过程,需要将删除点之后的元素向前移动一个位置。需要注意的是为了让GC起作用,必须显式的为最后一个位置赋null
值。
参考:
https://zhuanlan.zhihu.com/p/27873515
http://www.cnblogs.com/CarpenterLee/p/5419880.html
__EOF__

本文链接:https://www.cnblogs.com/ludangxin/p/15468651.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏
· Manus爆火,是硬核还是营销?