ArrayList源码解析(1.8)
概述
ArrayList是一个集合,实现了List接口,底层是基于数组实现。
ArrayList容器中的数据都是有序的,并且可以存储null值。
ArrayList进行遍历时,可以通过iterator进行遍历,也可以通过下标获取元素。
ArrayList是非线程安全的。
数据结构
ArrayList底层是基于Object数组进行实现。
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
*/
transient Object[] elementData; // non-private to simplify nested class access
成员变量
/**
* 数组默认初始长度
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 主实例数组,主要用于创建数组长度为0时的默认值
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 空实例数组,主要用于初始化和数据校验
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* 用于存储ArrayList数据
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
* 数组列表的大小
*/
private int size;
构造方法
/**
* 无参构造方法
*/
public ArrayList() {
// 默认创建一个空实例的数组
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
* 有参构造方法,创建一个指定长度的数组
*/
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
// 指定长度大于0,创建指定大小的数组
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
// 指定长度等于0,创建空实例数组
this.elementData = EMPTY_ELEMENTDATA;
} else {
// 指定长度小于0,则抛出异常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
/**
* 有参构造方法,将集合转为数组
*/
public ArrayList(Collection<? extends E> c) {
// 将集合转为数组,并赋值给elementData
elementData = c.toArray();
// 将原集合大小赋值给size,并判断是否等于0
if ((size = elementData.length) != 0) {
// 如果c.toArray转换后的对象不是Object数组,将原数组进行拷贝,并给elementData赋值
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// 如果原集合为空,则创建空实例数组
this.elementData = EMPTY_ELEMENTDATA;
}
}
主要方法
add(E e)
步骤如下:
- 调用calculateCapacity方法计算数组容量,如果数组为空,则获取一个数组容量为10的数组容量;如果数组非空,则获取相应数量的数组容量。
- 得到数组容量后,将记录操作数(modCount,作用:快速失败机制)加1。
- 判断数组容量是否大于数组实际大小,如果大于,则进行扩容。
3.1. 获取现有数组长度,计算新的数组容量,默认新数组容量为原数组容量的1.5倍。
3.2. 如果扩容1.5倍后数组容量还小于实际数组容量,则新数组容量为传入的容量。
3.3. 如果新数组容量大于Integer最大值减8,再判断传入数组容量是否大于Integer最大值减8,如果大于,数组容量为Integer最大值,如果小于,数据容量为Integer最大值减8。
3.4. 数组扩容,并将原数据拷贝到新数组中。 - 在数组尾部添加元素。
/**
* 向ArrayList中添加元素
*/
public boolean add(E e) {
// 扩容操作
ensureCapacityInternal(size + 1); // Increments modCount!!
// 在数组末尾添加元素
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
/**
* 计算数组容量大小
*/
private static int calculateCapacity(Object[] elementData, int minCapacity) {
// 如果当前数组为空,则比对传入数组容量大小和默认数组容量大小,取最大值
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
// 如果当前数组不为空,则返回传入的容量大小
return minCapacity;
}
/**
* 记录操作数,以及判断是否需要扩容
*/
private void ensureExplicitCapacity(int minCapacity) {
// 增加操作数
modCount++;
// 如果新的数组容量大于当前数组的长度,则进行扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/**
* 数组扩容
*/
private void grow(int minCapacity) {
// 当前数组长度
int oldCapacity = elementData.length;
// 计算新的数组容量,默认新数组容量为原数组容量的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 如果扩容后的数组容量还小于实际数组容量,则新数组容量为传入的容量
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 如果新数组容量大于Integer最大值减8,再判断传入数组容量是否大于Integer最大值减8,如果大于,数组容量为Integer最大值,如果小于,数据容量为Integer最大值减8
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 将当前数组拷贝至指定容量大小的新数组,并赋值给当前数组
elementData = Arrays.copyOf(elementData, newCapacity);
}
/**
* 获取最大数组容量
*/
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南