ArrayList 源码分析
ArrayList 是 Java 中比较常用的集合之一。它实现了 List
上面实现的 List 和 Serializable 接口可能大家都没什么疑惑,但是 RandomAccess 和 Cloneable 呢?我们看 RandomAccess 和 Cloneable 的源码,发现这两个接口都是空的。


其实这两个空的接口都是标记型接口,什么意思呢?就是来标记一个类是否属于使用快速随机访问个 clone() 方法的标记。
比如标记型接口是怎么标记是否可以使用快速随机访问的呢?在集合类 Collections 中我们可以看到:

是否实现了 RandomAccess 接口使用的搜索方法是不一样的。那么 Cloneable 的标记呢?我们知道 clone() 方法是 Object 类的,所以直接来看 Object 的源码:

我们看到了,如果没有实现 Cloneable 接口而使用 clone() 方法的话是会抛出 CloneNotSupportedException。所以类似于 RandomAccess 和 Cloneable 这样没有实体的接口在 Java 中被称为标记型接口,用来标记一个类或者接口。
主要参数
接下来我们看一下 ArrayList 的主要参数:
1 | // ArrayList 的默认容量 |
构造方法
接下来我们看一下 ArrayList 的构造方法,ArrayList 有三个构造方法:
1 | // 传入一个容量 |
我们来看一下 Arrays 中的 copyof 干了啥?
1 | public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) { |
我们看到在 ArrayList 的第三个构造方法中,传入的新类型也是 Object,所以它这里调用 Arrays.copyof 是为了将 elementData 转为 Object 数组。
add()、set()、get()
在集合类中,get()、和 add() / set() / put() 无疑是最重要的几个方法,我们先来看看 ArrayList 中的 add() 方法,ArrayList 中有两个 add() 方法:
1 | // 将元素添加到数组末尾 |
在看第二个 add() 方法之前,我们需要先看一下 System.arraycopy() 这个方法:
1 |
|
这个方法在源码中是一个 native 方法,是一个快速拷贝数组的方法,这个方法是指我们将数组 src 从位置 srcPos 开始,拷贝到从 destPos 位置开始的数组 dest 中,一共拷贝 length 个元素:

现在我们可以来看看第二个 add() 方法了:
1 | // 将元素添加到数组固定位置 |
那我们 ArrayList 中调用的 System.arraycopy(elementData, index, elementData, index + 1,size - index) 其实就是把数组 elementData 中的数组从 index 位往后移一位。
ArrayList 还提供了 set() 方法:
1 | public E set(int index, E element) { |
ArrayList 的 get() 比较简单,就是返回了数组中指定 index 的元素:
1 | public E get(int index) { |
ArrayList 中的扩容
在上面的 add() 方法中,我们看到了有一个保证内部容量的方法 ensureCapacityInternal(),那这个方法具体是怎么样的呢?
1 | // minCapacity 为要保证内部容量的最低值,add() 方法中为 size+1 |
1 | private void ensureExplicitCapacity(int minCapacity) { |
1 | private void grow(int minCapacity) { |
而 hugeCapacity() 这个方法是给 ArrayList 取极限值容量的:
1 | private static int hugeCapacity(int minCapacity) { |
再看看 remove() 方法
ArrayList 中的 remove() 方法也有两个,我们先来看看第一个:
1 | // 通过下标移除元素 |
我们再看看第二个方法:
1 | // 通过元素移除移除元素,返回是否操作成功 |
那么快速移除是怎么具体实现呢?
1 | // 我们可以看到,fastRemove() 方法与第一个 remove() 方法差不多一样的 |
总结
通过这次的 ArrayList 源码分析,我们可以看到 ArrayList 的查询是非常快的,但是增删都比较慢,add() 如果是直接添加到末尾还好说,如果添加到中间,数组后面的元素是全部需要移动的,而删除时,不管是哪种方式,都是需要移动数组,就导致增删比较慢。当然这里的慢一般是比较少见的,平时我们使用的场景的数组元素的个数一般来说是感受不到这种快慢的,但是呢,我们了解了其内部结构过后我们也可以按照场景选择不同的集合类了。
好了,ArrayList 的源码就分享到这里了,如果想要一起学习的话,可以持续关注这个 GitHub项目,或者关注我的个人微信公众号。

觉得喜欢的话请给我这个 GitHub 项目 一个 Star,谢谢!