概述
1.数据存储是基于动态数组实现的,默认初始容量为10。
2.添加数据时,首先需要检查元素个数是否超过数组容量,如果超过了则需要对数组进行扩容(1.5倍);插入数据时,需要将从插入点 k 开始到数组末尾的数据全部向后移动一位。
3.数组的扩容是新建一个大容量(原数组大小 + 扩容容量)的数组,然后将原数组的数据拷贝到新数组。数组扩容操作的代价比较高,如果能预估数据量,那么就给 ArrayList 分配一个较大的初始值,可以减少调整大小的开销,ArrayList支持缩容,但不会自动缩容。
4.删除数据时,需要将从删除点+1位置开始到数组末尾的数据全部向前移动一位。
5.访问数据很快,根据索引可以直接获取。
父类和接口
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
ArrayList 继承了 AbstractList,实现了 List 接口。而AbstractList 已经实现了 List 接口,这里的重复实现使得接口功能更加清晰,JDK中很多类都是如此。Cloneable 接口是克隆标记接口,Serializable 是序列化标记接口,要实现 clone 和 序列化功能必须实现这两个接口。而 RandomAccess 单纯是一个标记接口,它表示该类支持快速随机访问,且在循环遍历时,for循环会优于迭代器。
成员变量
private static final long serialVersionUID = 8683452581122892189L;
private static final int DEFAULT_CAPACITY = 10;
private static final Object[] EMPTY_ELEMENTDATA = {};
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
transient Object[] elementData;
private int size;
1.serialVersionUID 的作用就是为了保证序列化和反序列化的一致性。当 ArrayList 发生变更时,只要保持 serialVersionUID 不变,就可以确保序列化后的数据能够正确地反序列化回原来的 ArrayList 对象。
2.默认初始容量为10。
3.当创建一个 ArrayList 时,如果没有指定初始容量,那么 ArrayList 就会使用这个 EMPTY_ELEMENTDATA 作为其底层数组。
4.当用户使用无参构造器创建一个 ArrayList 时,ArrayList 会将底层数组初始化为这个 DEFAULTCAPACITY_EMPTY_ELEMENTDATA。这个数组和 EMPTY_ELEMENTDATA 的区别在于,当第一次向 ArrayList 添加元素时,ArrayList 会将底层数组扩容到默认的初始容量 (通常是 10)。而 EMPTY_ELEMENTDATA 则不会进行这种扩容操作。
5.当 ArrayList 被序列化时,transient 关键字会告诉 Java 虚拟机忽略这个字段,不对它进行序列化。当 ArrayList 被反序列化时,elementData 会被重新初始化为一个默认的空数组。
6.元素的实际数量。