概述
ArrayList是List接口的可变数组的实现。实现了所有可选列表操作,并允许包括 null 在内的所有元素。除了实现 List 接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小。
每个ArrayList实例都有一个容量,该容量是指用来存储列表元素的数组的大小。它总是至少等于列表的大小。随着向ArrayList中不断添加元素,其容量也自动增长。自动增长会带来数据向新数组的重新拷贝,因此,如果可预知数据量的多少,可在构造ArrayList时指定其容量。在添加大量元素前,应用程序也可以使用ensureCapacity操作来增加ArrayList实例的容量,这可以减少递增式再分配的数量。
注意,不是线程安全的。
ArrayList的实现
- 底层数组实现
/** * Default initial capacity. */
private static final int DEFAULT_CAPACITY = 10;
transient Object[] elementData;
// non-private to simplify nested class access
private static final Object[]
DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; - 构造函数, 三个构造函数
//指定具体的容量
public ArrayList(int initialCapacity)
//默认空数组组,DEFAULTCAPACITY_EMPTY_ELEMENTDATA
public ArrayList()
//构造一个包含指定collection的元素的列表,这些元素按照该collection的迭代器返回它们的顺序排列的
public ArrayList(Collection<? extends E> c) - 调整容量trimToSize
ArrayList还给我们提供了将底层数组的容量调整为当前列表保存的实际元素的大小的功能。它可以通过trimToSize方法来实现
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = (size == 0)?EMPTY_ELEMENTDATA :Arrays.copyOf(elementData, size); }} - 调整容量ensureCapacity
//根据给定的容量进行调整,如果大于当前数组的长度,那么调整的容量是1.5倍
//int newCapacity = oldCapacity + (oldCapacity >> 1);
public void ensureCapacity(int minCapacity) - 增加数组
//向数组末尾添加元素
public boolean add(E e) - 插入元素
//插入位置往后的元素都需要后移,另外会首先判断是否需要扩容
public void add(int index, E element) - 删除元素
// 移除此列表中指定位置上的元素.
public boolean remove(Object o) - 删除指定索引的元素
//移除指定索引的元素,该操作使用系统函数arraycopy来实现数组的复制,并且所有删除位置后面的元素左移
private void fastRemove(int index) - 添加集合
//添加集合,需要判断是否需要扩容,仍然是数组的复制。
public boolean addAll(Collection<? extends E> c) - Fail-Fash
Fail-Fast机制:ArrayList也采用了快速失败的机制,通过记录modCount参数来实现。
在面对并发的修改时,迭代器很快就会完全失败,而不是冒着在将来某个不确定时间发生任意不确定行为的风险.
我们发现modCount在迭代器当中被使用,是在forEach中赋值给final int expectedModCount=modCount.
(而且是在不是线程安全的集合里都存在,比如HashMap,LinkedHashMap.)
如果在这个过程当中,判断这两个值不相等,那么跑出异常.