ArrayList源码
ArrayList源码
目录
一、ArrayList
-
ArrayList
中维护了一个Object数组:transient Object[] elementData;
transient
表示该属性不会被序列化,ArrayList自己实现了writeObject
方法和readObject
方法 -
当创建
ArrayList
对象时,如果使用的是无参构造,则初始的size为0,第一次添加时,则扩容为10,如需再次扩容,则扩容为原来的1.5倍 -
如果使用的是指定大小的构造器,则初始化容量为指定大小,如需再次扩容,则直接扩容为1.5倍
1.1 包含的属性
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
@java.io.Serial
private static final long serialVersionUID = 8683452581122892189L;
/**
* 默认的容量
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 用于空实例的共享空数组实例。
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 用于默认大小的空实例的共享空数组实例。
我们将其与 EMPTY_ELEMENTDATA 区分开来,以了解添加第一个元素时要膨胀多少。
当使用无参构造方法时,将会将此实例赋值给elementData
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* 存储 ArrayList 元素的数组缓冲区。
ArrayList 的容量就是这个数组缓冲区的长度。
当添加第一个元素时,任何具有
elementData ==DEFAULTCAPACITY_EMPTY_ELEMENTDATA 的空 ArrayList
都将扩展为 DEFAULT_CAPACITY。
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
* The size of the ArrayList (the number of elements it contains).
*
* @serial
*/
private int size;
}
1.2 源码分析
1.2.1 add源码分析
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return {@code true} (as specified by {@link Collection#add})
*/
public boolean add(E e) {
//修改次数+1
modCount++;
add(e, elementData, size);
return true;
}
/**
* 这个辅助方法从 add(E) 中分离出来,以将方法字节码大小保持在 35 以下
(-XX:MaxInlineSize 默认值),这有助于在 C1 编译的循环中调用 add(E) 时。
*/
//e-添加的元素,elementData-数组,s-当前数组的size
private void add(E e, Object[] elementData, int s) {
//判断当前数组的size==数组的长度
if (s == elementData.length)
//真:扩容
elementData = grow();
//将当前元素加入集合
elementData[s] = e;
//size+1
size = s + 1;
}
- 首先判断当前数组的size==数组的长度,如果为首次添加元素,那么s和elementData.length都等于0,因此,会进入扩容方法
1.2.2 grow源码
private Object[] grow() {
return grow(size + 1);
}
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
* @throws OutOfMemoryError if minCapacity is less than zero
*/
private Object[] grow(int minCapacity) {
//存储当前数组的长度
int oldCapacity = elementData.length;
//旧长度>0||当前数组!=DEFAULTCAPACITY_EMPTY_ELEMENTDATA
if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//真:计算新的数组长度,扩容为原来的1.5倍
int newCapacity = ArraysSupport.newLength(oldCapacity,
minCapacity - oldCapacity, /* minimum growth */
oldCapacity >> 1 /* preferred growth */);
//以新容量创建数组
return elementData = Arrays.copyOf(elementData, newCapacity);
} else {
//旧容量为0,当前数组==DEFAULTCAPACITY_EMPTY_ELEMENTDATA,则创建默认容量的集合
return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
}
}
//ArraysSupport.newLength
public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
// assert oldLength >= 0
// assert minGrowth > 0
int newLength = Math.max(minGrowth, prefGrowth) + oldLength;
if (newLength - MAX_ARRAY_LENGTH <= 0) {
return newLength;
}
//
return hugeLength(oldLength, minGrowth);
}
📌可以看到再
grow()
方法中用到了ArraySupport
和Arrays
两个类,其中ArraySupport
里面实现了很多方法来支持数组操作,包括查找两个数组的不匹配,以及为需要重新分配地址的数组计算新的长度。Arrays
类里面实现了很多对数组进行操作的方法(比如排序、查找)Arrays.copyOf
方法实现了将旧数组元素迁移到新的数组中,里面调用了System.arraycopy
方法(native方法)实现
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)