Java集合之ArrayList源码篇

☆* o(≧▽≦)o *☆嗨~我是小奥🍹
📄📄📄个人博客:小奥的博客
📄📄📄CSDN:个人CSDN
📙📙📙Github:传送门
📅📅📅面经分享(牛客主页):传送门
🍹文章作者技术和水平有限,如果文中出现错误,希望大家多多指正!
📜 如果觉得内容还不错,欢迎点赞收藏关注哟! ❤️

Java集合之ArrayList源码详解

概述

ArrayList实现了List接口,是顺序容器,即元素存放的数据与放进去的顺序相同,允许放入null元素,底层通过数组实现

public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
  • 继承AbstractList类,提供了相关修改、删除、遍历等功能
  • 实现RandomAccess,空接口,作为随机访问的标志,代表只要实现了这个接口,就能支持快速随机访问。在ArrayList中,我们可以通过元素的序号快速获取元素对象,这就是快速随机访问。
  • 实现Cloneable,空接口,作为支持克隆的标志,实现这个接口后,在类中重写Object的clone方法,后面通过调用clone()才能克隆成功,如果实现这个接口,则会抛出CloneNotSupportedException(克隆不被支持)异常。
  • 实现Serialization,空接口,作为可以实现序列化和反序列化的标志。

底层数据结构

构造函数

ArrayList有三个构造函数,参数分别是 空参initialCapacityCollection<? extends E> c

/**
* 带初始容量参数的构造函数(用户可以在创建ArrayList对象时自己指定集合的初始大小)
*/
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
// 如果传入参数大于0,创建initialCapacity大小的数组
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
// 如果传入参数等于0,则创建空数组
this.elementData = EMPTY_ELEMENTDATA;
} else {
// 其他情况则抛出异常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}

/**
* 默认无参构造函数
* DEFAULTCAPACITY_EMPTY_ELEMENTDATA 为0,初始化为10,
* 也就是说初始其实是空数组 当添加第一个元素的时候数组容量才变成10
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

/**
* 构造一个包含指定集合元素的列表。按照指定集合的迭代器返回的顺序。
*/
public ArrayList(Collection<? extends E> c) {
// 将指定集合转换为数组
Object[] a = c.toArray();
if ((size = a.length) != 0) {
// 如果elementData数组的长度不为0
if (c.getClass() == ArrayList.class) {
// 如果数组元素是ArrayList类型,则直接覆盖elementData
elementData = a;
} else {
// 如果不是ArrayList类型,赋值给新的Object类型的elementData
elementData = Arrays.copyOf(a, size, Object[].class);
}
} else {
// 其他情况,用空数组代替
elementData = EMPTY_ELEMENTDATA;
}
}

根据源码可以得知:

  • 如果指定容量:
    • initialCapacity > 0,则使用initialCapacity容量创建数组;
    • initialCapacity = 0, 则默认创建空数组;
    • initialCapacity < 0,抛出Illegal ArgumentException异常。
  • 如果不指定容量:
    • 直接默认使用创建空数组。

扩容原理

扩容流程如下:

1、ArrayList的扩容是通过add方法来触发的,在add元素之前首先尝试将容量 + 1,判断是否需要扩容。

2、通过计算得到最小扩容量。如果底层数组为空,则得到传入的容量与默认初始容量10之间的最大值。

3、判断是否需要扩容,如果需要的最小容量大于目前的长度,那么就去扩容,否则就不进行扩容。

4、扩容的核心是将容量扩大到原来的1.5倍,如果新容量比最小扩容容量还要小,那么就把新容量 = 最小扩容容量;如果新容量大于最大的容量(Integer.MAX_VALUE - 8),那么将进行判断,如果指定的容量小于0,则抛出异常,如果大于最大容量,则新容量为 Integer.MAX_VALUE,否则等于最大容量。

5、扩容之后将数组拷贝返回。调用Arrays.copyOf()方法复制数组,其底层还是调用了本地方法System.arraycopy()

下面我们一起分析一下这个流程。

add触发扩容

ArrayList的扩容是通过add方法来触发的,在add元素之前首先尝试将容量 + 1,判断是否需要扩容。

/**
* 将指定的元素追加到此列表的末尾。
*/
public boolean add(E e) {
// 确保容量足够
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}

ensureCapacityInternal检查

// 确保内部容量达到指定的最小容量。
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

//判断是否需要扩容
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
if (minCapacity - elementData.length > 0)
// 调用grow方法进行扩容
grow(minCapacity);
}

calculateCapacity 计算容量

通过计算得到最小扩容量。如果底层数组为空,则得到传入的容量与默认初始容量10之间的最大值。

// 根据给定的最小容量和当前数组元素来计算所需的容量 
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// 如果当前数组元素为空数组(初始情况),则返回 max(默认容量,最小容量)
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
// 否则直接返回最小容量
return minCapacity;
}

grow进行扩容

扩容的核心是将容量扩大到原来的1.5倍,如果新容量比最小扩容容量还要小,那么就把新容量 = 最小扩容容量;如果新容量大于最大的容量(Integer.MAX_VALUE - 8),那么将进行判断,如果指定的容量小于0,则抛出异常,如果大于最大容量,则新容量为 Integer.MAX_VALUE,否则等于最大容量。

/**
* 要分配的最大数组大小
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

/**
* 增加容量以确保它至少可以容纳最小容量参数指定的元素数量。
*/
private void grow(int minCapacity) {
// oldCapacity为旧容量,newCapacity为新容量
int oldCapacity = elementData.length;
// oldCapacity >> 1,相当于 oldCapacity/2
// 将新容量更新为旧容量的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 检查新容量
if (newCapacity - minCapacity < 0)
// 如果小于最小需要容量,那么将最小需要容量当作新容量
newCapacity = minCapacity;
// 检查新容量是否超出了ArrayList定义的最大容量
if (newCapacity - MAX_ARRAY_SIZE > 0)
// 如果超出了,则调用hugeCapacity()来比较minCapacity和MAX_ARRAY_SIZE
newCapacity = hugeCapacity(minCapacity);
// 调用Arrays.copyOf复制数组元素
elementData = Arrays.copyOf(elementData, newCapacity);
}

// 比较minCapacity和 MAX_ARRAY_SIZE
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}

Arrays.copy数组拷贝

扩容之后将数组拷贝返回。调用Arrays.copyOf()方法复制数组,其底层还是调用了本地方法System.arraycopy()

// java.util.Arrays#copyOf(U[], int, java.lang.Class<? extends T[]>)
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
   /**
* 复制数组,属于浅拷贝
* @param src 源数组
* @param srcPos 源数组中的起始位置
* @param dest 目标数组
* @param destPos 目标数组中的起始位置
* @param length 要复制的数组元素的数量
*/
// java.lang.System#arraycopy
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);

验证System.arraycopy是浅拷贝

public class Test {
public static void main(String[] args) {
Student[] students = new Student[]{
new Student(1,"小明"),
new Student(2,"小红"),
new Student(3,"小黑"),
new Student(4,"小白")
};
Student[] target = new Student[students.length];
System.arraycopy(students, 0, target, 0, students.length);
System.out.println("源对象是否和复制后的目标对象一致: " + ((students[0].equals(target[0])) ? "浅拷贝" : "深拷贝"));

// 打印复制后的目标数组
System.out.println(Arrays.toString(target));

// 更改target数组
target[0].setName("测试");

System.out.println("student[0].getName() = " + students[0].getName());
}
}

控制台输出以下内容:

源对象是否和复制后的目标对象一致: 浅拷贝
[Student{id=1, name='小明'}, Student{id=2, name='小红'}, Student{id=3, name='小黑'}, Student{id=4, name='小白'}]
student[0].getName() = 测试

复制的过程如下:

image-20240111211910140

ArrayList面试题总结

ArrayList在JDK1.7和JDK1.8的区别

在JDK1.7的时候,创建集合不指定容量时,底层直接创建了长度为10的Object数组,然后在调用add()方法向集合中添加元素时,才会考虑扩容的问题。

在JDK1.8的时候,创建集合不指定容量时,底层的Object数组初始化为空,只有在第一次调用add()方法的时候,才会初始化数组。

这样做的目的可以节省内存的消耗,因为在添加元素时数组名将指针指向了新的数组且老数组是一个空数组这样有利于System.gc(),并不会一直占据内存。

JDK1.7中list的创建,类似于单例模式中的饿汉式,在初始化的时候就创建好;而1.8中,则类似于单例模式中的懒汉式,采用延迟加载,节省内存空间。

ArrayList和LinkedList的区别

(1)是否保证线程安全: ArrayListLinkedList 都是不同步的,也就是不保证线程安全;

(2)底层数据结构: Arraylist 底层使用的是 Object 数组LinkedList 底层使用的是 双向链表 数据结构(JDK1.6 之前为循环链表,JDK1.7 取消了循环)

(3)存取效率:ArrayList底层使用数组实现,所以它的查找时间复杂度是O(1),插入和删除时间复杂度是O(n);而LinkedList底层使用链表实现的,所以它的查找时间复杂度是O(n),插入和删除只需要改变元素指针的指向即可,所以是O(1)。

(4)内存空间占用: ArrayList 的空间浪费主要体现在在 list 列表的结尾会预留一定的容量空间,而 LinkedList 的空间花费则体现在它的每一个元素都需要消耗比 ArrayList 更多的空间(因为要存放直接后继和直接前驱以及数据)。

ArrayList和Vector的区别

(1)是否线程安全:ArrayList线程不安全,而Vector是线程安全的。

(2)底层数据结构:两者底层都是使用数组实现的。

ArrayList扩容流程

(1)第一步,在add方法添加元素的时候,首先尝试将size + 1,判断是否需要扩容;

(2)第二步,通过计算得到最小扩容量。如果数组是默认的空数组,那么会取最小扩容量和默认容量10之间的最大值作为新的最小容量,然后拿这个最小容量去判断是否需要扩容。

(3)第三步,如果最小容量比当前数组的长度还大,则进行扩容。

(4)第四步,先将旧容量扩大1.5倍作为新容量,如果新容量小于最小容量,则将最小容量作为新容量;如果新容量大于最大容量(Integer.MAX_VALUE - 8),那么去调整新容量。如果新容量小于0,则抛出OutOfMemoryError()异常,否则将新容量设置为Integer.MAX_VALUE

(5)第五步,调用Arrays.copyOf()方法拷贝数组到原数组。

ArrayList可以添加null值吗

ArrayList 中可以存储任何类型的对象,包括 null 值。不过,不建议向ArrayList 中添加 null 值, null 值无意义,会让代码难以维护比如忘记做判空处理就会导致空指针异常。

源码

以下ArrayList源码版本为JDK8

package java.util;

import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import sun.misc.SharedSecrets;

public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
private static final long serialVersionUID = 8683452581122892189L;

/**
* 默认初始容量大小
*/
private static final int DEFAULT_CAPACITY = 10;

/**
* 空数组(用于空实例)
*/
private static final Object[] EMPTY_ELEMENTDATA = {};

/**
* 用于默认大小空实例的共享空数组实例。
* 我们把它从EMPTY_ELEMENTDATA数组中区分出来,以知道在添加第一个元素时容量需要增加多少。
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

/**
* 存储ArrayList元素的数组缓冲区。
* ArrayList容量就是这个数组缓冲区的长度。任何带有 elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* 的空数组列表将在添加第一个元素时扩展为DEFAULT_CAPACITY。
*/
transient Object[] elementData; // non-private to simplify nested class access

/**
* ArrayList 所包含的元素个数
*/
private int size;

/**
* 带初始容量参数的构造函数(用户可以在创建ArrayList对象时自己指定集合的初始大小)
*/
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
// 如果传入参数大于0,创建initialCapacity大小的数组
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
// 如果传入参数等于0,则创建空数组
this.elementData = EMPTY_ELEMENTDATA;
} else {
// 其他情况则抛出异常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}

/**
* 默认无参构造函数
* DEFAULTCAPACITY_EMPTY_ELEMENTDATA 为0,初始化为10,
* 也就是说初始其实是空数组 当添加第一个元素的时候数组容量才变成10
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

/**
* 构造一个包含指定集合元素的列表。按照指定集合的迭代器返回的顺序。
*/
public ArrayList(Collection<? extends E> c) {
// 将指定集合转换为数组
Object[] a = c.toArray();
if ((size = a.length) != 0) {
// 如果elementData数组的长度不为0
if (c.getClass() == ArrayList.class) {
// 如果数组元素是ArrayList类型,则直接覆盖elementData
elementData = a;
} else {
// 如果不是ArrayList类型,赋值给新的Object类型的elementData
elementData = Arrays.copyOf(a, size, Object[].class);
}
} else {
// 其他情况,用空数组代替
elementData = EMPTY_ELEMENTDATA;
}
}

/**
* 将这个ArrayList实例的容量调整为列表的当前大小。
* 应用程序可以使用此操作来最小化ArrayList实例的存储空间。
*/
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}

/**
* 如果有必要,增加这个ArrayList实例的容量,以确保它至少可以容纳最小容量参数指定的元素数量。
*/
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// any size if not default element table
? 0
// larger than default for default empty table. It's already
// supposed to be at default size.
: DEFAULT_CAPACITY;

if (minCapacity > minExpand) {
// 如果最小容量大于已有的最大容量,计算需要的容量
ensureExplicitCapacity(minCapacity);
}
}

// 根据给定的最小容量和当前数组元素来计算所需的容量
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// 如果当前数组元素为空数组(初始情况),则返回 max(默认容量,最小容量)
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
// 否则直接返回最小容量
return minCapacity;
}

// 确保内部容量达到指定的最小容量。
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

//判断是否需要扩容
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
if (minCapacity - elementData.length > 0)
// 调用grow方法进行扩容
grow(minCapacity);
}

/**
* 要分配的数组的最大大小。有些虚拟机在数组中保留一些头字。
* 尝试分配更大的数组可能会导致OutOfMemoryError:请求的数组大小超过虚拟机限制
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

/**
* 增加容量以确保它至少可以容纳最小容量参数指定的元素数量。
*/
private void grow(int minCapacity) {
// oldCapacity为旧容量,newCapacity为新容量
int oldCapacity = elementData.length;
// oldCapacity >> 1,相当于 oldCapacity/2
// 将新容量更新为旧容量的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 检查新容量
if (newCapacity - minCapacity < 0)
// 如果小于最小需要容量,那么将最小需要容量当作新容量
newCapacity = minCapacity;
// 检查新容量是否超出了ArrayList定义的最大容量
if (newCapacity - MAX_ARRAY_SIZE > 0)
// 如果超出了,则调用hugeCapacity()来比较minCapacity和MAX_ARRAY_SIZE
newCapacity = hugeCapacity(minCapacity);
// 调用Arrays.copyOf复制数组元素
elementData = Arrays.copyOf(elementData, newCapacity);
}

// 比较minCapacity和 MAX_ARRAY_SIZE
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}

/**
* 返回此列表中的元素数。
*/
public int size() {
return size;
}

/**
* 如果此列表不包含元素,则返回 true 。
*/
public boolean isEmpty() {
return size == 0;
}

/**
* 如果此列表包含指定的元素,则返回true 。
*/
public boolean contains(Object o) {
return indexOf(o) >= 0;
}

/**
* 返回此列表中指定元素的首次出现的索引,如果此列表不包含此元素,则为-1。
*/
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}

/**
* 返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1。
*/
public int lastIndexOf(Object o) {
if (o == null) {
for (int i = size-1; i >= 0; i--)
if (elementData[i]==null)
return i;
} else {
for (int i = size-1; i >= 0; i--)
if (o.equals(elementData[i]))
return i;
}
return -1;
}

/**
* 返回此ArrayList实例的浅拷贝。(元素本身不被复制。)
*/
public Object clone() {
try {
ArrayList<?> v = (ArrayList<?>) super.clone();
// Arrays.copyOf功能是实现数组的复制,返回复制后的数组。参数是被复制的数组和复制的长度。
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// 这不应该发生,因为我们是可以克隆的
throw new InternalError(e);
}
}

/**
* 以正确的顺序(从第一个到最后一个元素)返回一个包含此列表中所有元素的数组。
* 返回的数组将是“安全的”,因为该列表不保留对它的引用。 (换句话说,这个方法必须分配一个新的数组)。
* 因此,调用者可以自由地修改返回的数组。 此方法充当基于阵列和基于集合的API之间的桥梁。
*/
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}

/**
* 返回一个数组,其中包含列表中所有元素的正确顺序(从第一个元素到最后一个元素);
* 返回数组的运行时类型为指定数组的运行时类型。
* 如果列表适合指定的数组,它将在指定的数组中返回。
* 否则,将使用指定数组的运行时类型和此列表的大小分配一个新数组。
* 如果列表适合指定的数组,并且有足够的空间(即数组的元素多于列表),则数组中紧接在集合末尾的元素被设置为空。
* (只有当调用者知道列表不包含任何null元素时,这在确定列表长度时才有用。)
*/
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
if (a.length < size)
// 新建一个运行时类型的数组,但是元素是ArrayList的元素
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
// 调用System.arraycopy实现数组之间的复制
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}

// Positional Access Operations

@SuppressWarnings("unchecked")
E elementData(int index) {
return (E) elementData[index];
}

/**
* 返回此列表中指定位置的元素。
*/
public E get(int index) {
rangeCheck(index);

return elementData(index);
}

/**
* 用指定的元素替换此列表中指定位置的元素。
*/
public E set(int index, E element) {
// 界限检查
rangeCheck(index);

E oldValue = elementData(index);
elementData[index] = element;
// 返回原来在这个位置的元素
return oldValue;
}

/**
* 将指定的元素追加到此列表的末尾。
*/
public boolean add(E e) {
// 确保容量足够
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}

/**
* 在此列表中的指定位置插入指定的元素。
*
*/
public void add(int index, E element) {
// 界限检查
rangeCheckForAdd(index);

// 确保容量足够
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}

/**
* 删除该列表中指定位置的元素。 将任何后续元素移动到左侧(从其索引中减去一个元素)。
*/
public E remove(int index) {
rangeCheck(index);

modCount++;
E oldValue = elementData(index);

int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work

return oldValue;
}

/**
* 从列表中删除指定元素的第一个出现(如果存在)。 如果列表不包含该元素,则它不会更改。
* 返回true,如果此列表包含指定的元素
*/
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}

/*
* 跳过边界检查而不返回移除的值的私有删除方法。
*/
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
}

/**
* 从列表中删除所有元素。
*/
public void clear() {
modCount++;

// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;

size = 0;
}

/**
* 按指定集合的Iterator返回的顺序将指定集合中的所有元素追加到此列表的末尾。
*/
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}

/**
* 将指定集合中的所有元素插入到此列表中,从指定的位置开始。
*/
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);

Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount

int numMoved = size - index;
if (numMoved > 0)
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved);

System.arraycopy(a, 0, elementData, index, numNew);
size += numNew;
return numNew != 0;
}

/**
* 从此列表中删除所有索引为fromIndex (含)和toIndex之间的元素。
* 将任何后续元素移动到左侧(减少其索引)。
*/
protected void removeRange(int fromIndex, int toIndex) {
modCount++;
int numMoved = size - toIndex;
System.arraycopy(elementData, toIndex, elementData, fromIndex,
numMoved);

// clear to let GC do its work
int newSize = size - (toIndex-fromIndex);
for (int i = newSize; i < size; i++) {
elementData[i] = null;
}
size = newSize;
}

/**
* 检查给定的索引是否在范围内。
* 如果不是,则抛出适当的运行时异常。
* 该方法“不”检查索引是否为负:它总是在数组访问之前立即使用,
* 如果索引为负,则抛出ArrayIndexOutOfBoundsException。
*/
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

/**
* add和addAll使用的rangeCheck的一个版本。
*/
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

/**
* 构造IndexOutOfBoundsException详细消息。
* 在许多可能的错误处理代码重构中,这种“概述”在服务器和客户端vm中都表现最好。
*/
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+size;
}

/**
* 元素中包含的所有元素从此列表中删除指定的集合。
*/
public boolean removeAll(Collection<?> c) {
Objects.requireNonNull(c);
// 如果此列表被修改则返回true
return batchRemove(c, false);
}

/**
* 仅保留此列表中包含在指定集合中的元素。
* 换句话说,从列表中删除所有未包含在指定集合中的其元素的。
*/
public boolean retainAll(Collection<?> c) {
Objects.requireNonNull(c);
return batchRemove(c, true);
}

private boolean batchRemove(Collection<?> c, boolean complement) {
final Object[] elementData = this.elementData;
int r = 0, w = 0;
boolean modified = false;
try {
for (; r < size; r++)
if (c.contains(elementData[r]) == complement)
elementData[w++] = elementData[r];
} finally {
// Preserve behavioral compatibility with AbstractCollection,
// even if c.contains() throws.
if (r != size) {
System.arraycopy(elementData, r,
elementData, w,
size - r);
w += size - r;
}
if (w != size) {
// clear to let GC do its work
for (int i = w; i < size; i++)
elementData[i] = null;
modCount += size - w;
size = w;
modified = true;
}
}
return modified;
}

/**
* 将ArrayList实例的状态保存到一个流中(即序列化它)。
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject();

// Write out size as capacity for behavioural compatibility with clone()
s.writeInt(size);

// Write out all elements in the proper order.
for (int i=0; i<size; i++) {
s.writeObject(elementData[i]);
}

if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}

/**
* 从流重新构造ArrayList实例(即反序列化它)。
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
elementData = EMPTY_ELEMENTDATA;

// Read in size, and any hidden stuff
s.defaultReadObject();

// Read in capacity
s.readInt(); // ignored

if (size > 0) {
// be like clone(), allocate array based upon size not capacity
int capacity = calculateCapacity(elementData, size);
SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, capacity);
ensureCapacityInternal(size);

Object[] a = elementData;
// Read in all elements in the proper order.
for (int i=0; i<size; i++) {
a[i] = s.readObject();
}
}
}

/**
* 返回遍历此列表中元素的列表迭代器(以适当的顺序),从列表中的指定位置开始。
* 指定的索引指示初始调用next将返回的第一个元素。对previous的初始调用将返回具有指定索引- 1的元素。
*/
public ListIterator<E> listIterator(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: "+index);
return new ListItr(index);
}

/**
* 返回一个遍历此列表中元素的列表迭代器(按适当的顺序)。
* 返回的列表迭代器是快速失败的。
*/
public ListIterator<E> listIterator() {
return new ListItr(0);
}

/**
* 按适当顺序返回遍历列表中元素的迭代器。
* 返回的迭代器是快速失败的。
*/
public Iterator<E> iterator() {
return new Itr();
}

/**
* AbstractList的优化版本。Itr
*/
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;

Itr() {}

public boolean hasNext() {
return cursor != size;
}

@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}

public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();

try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}

@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = ArrayList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[i++]);
}
// update once at end of iteration to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
}

final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}

/**
* AbstractList的优化版本。ListItr
*/
private class ListItr extends Itr implements ListIterator<E> {
ListItr(int index) {
super();
cursor = index;
}

public boolean hasPrevious() {
return cursor != 0;
}

public int nextIndex() {
return cursor;
}

public int previousIndex() {
return cursor - 1;
}

@SuppressWarnings("unchecked")
public E previous() {
checkForComodification();
int i = cursor - 1;
if (i < 0)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i;
return (E) elementData[lastRet = i];
}

public void set(E e) {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();

try {
ArrayList.this.set(lastRet, e);
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}

public void add(E e) {
checkForComodification();

try {
int i = cursor;
ArrayList.this.add(i, e);
cursor = i + 1;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}

/**
* 返回该列表中介于指定的fromIndex(包含)和toIndex(不包含)之间的部分的视图。
* (如果fromIndex和toIndex相等,返回的列表为空。)返回的列表由此列表支持,
* 因此返回列表中的非结构性更改反映在此列表中,反之亦然。返回的列表支持所有可选的列表操作。
*/
public List<E> subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size);
return new SubList(this, 0, fromIndex, toIndex);
}

static void subListRangeCheck(int fromIndex, int toIndex, int size) {
if (fromIndex < 0)
throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
if (toIndex > size)
throw new IndexOutOfBoundsException("toIndex = " + toIndex);
if (fromIndex > toIndex)
throw new IllegalArgumentException("fromIndex(" + fromIndex +
") > toIndex(" + toIndex + ")");
}

private class SubList extends AbstractList<E> implements RandomAccess {
private final AbstractList<E> parent;
private final int parentOffset;
private final int offset;
int size;

SubList(AbstractList<E> parent,
int offset, int fromIndex, int toIndex) {
this.parent = parent;
this.parentOffset = fromIndex;
this.offset = offset + fromIndex;
this.size = toIndex - fromIndex;
this.modCount = ArrayList.this.modCount;
}

public E set(int index, E e) {
rangeCheck(index);
checkForComodification();
E oldValue = ArrayList.this.elementData(offset + index);
ArrayList.this.elementData[offset + index] = e;
return oldValue;
}

public E get(int index) {
rangeCheck(index);
checkForComodification();
return ArrayList.this.elementData(offset + index);
}

public int size() {
checkForComodification();
return this.size;
}

public void add(int index, E e) {
rangeCheckForAdd(index);
checkForComodification();
parent.add(parentOffset + index, e);
this.modCount = parent.modCount;
this.size++;
}

public E remove(int index) {
rangeCheck(index);
checkForComodification();
E result = parent.remove(parentOffset + index);
this.modCount = parent.modCount;
this.size--;
return result;
}

protected void removeRange(int fromIndex, int toIndex) {
checkForComodification();
parent.removeRange(parentOffset + fromIndex,
parentOffset + toIndex);
this.modCount = parent.modCount;
this.size -= toIndex - fromIndex;
}

public boolean addAll(Collection<? extends E> c) {
return addAll(this.size, c);
}

public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
int cSize = c.size();
if (cSize==0)
return false;

checkForComodification();
parent.addAll(parentOffset + index, c);
this.modCount = parent.modCount;
this.size += cSize;
return true;
}

public Iterator<E> iterator() {
return listIterator();
}

public ListIterator<E> listIterator(final int index) {
checkForComodification();
rangeCheckForAdd(index);
final int offset = this.offset;

return new ListIterator<E>() {
int cursor = index;
int lastRet = -1;
int expectedModCount = ArrayList.this.modCount;

public boolean hasNext() {
return cursor != SubList.this.size;
}

@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= SubList.this.size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (offset + i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[offset + (lastRet = i)];
}

public boolean hasPrevious() {
return cursor != 0;
}

@SuppressWarnings("unchecked")
public E previous() {
checkForComodification();
int i = cursor - 1;
if (i < 0)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (offset + i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i;
return (E) elementData[offset + (lastRet = i)];
}

@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = SubList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (offset + i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[offset + (i++)]);
}
// update once at end of iteration to reduce heap write traffic
lastRet = cursor = i;
checkForComodification();
}

public int nextIndex() {
return cursor;
}

public int previousIndex() {
return cursor - 1;
}

public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();

try {
SubList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = ArrayList.this.modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}

public void set(E e) {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();

try {
ArrayList.this.set(offset + lastRet, e);
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}

public void add(E e) {
checkForComodification();

try {
int i = cursor;
SubList.this.add(i, e);
cursor = i + 1;
lastRet = -1;
expectedModCount = ArrayList.this.modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}

final void checkForComodification() {
if (expectedModCount != ArrayList.this.modCount)
throw new ConcurrentModificationException();
}
};
}

public List<E> subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size);
return new SubList(this, offset, fromIndex, toIndex);
}

private void rangeCheck(int index) {
if (index < 0 || index >= this.size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

private void rangeCheckForAdd(int index) {
if (index < 0 || index > this.size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+this.size;
}

private void checkForComodification() {
if (ArrayList.this.modCount != this.modCount)
throw new ConcurrentModificationException();
}

public Spliterator<E> spliterator() {
checkForComodification();
return new ArrayListSpliterator<E>(ArrayList.this, offset,
offset + this.size, this.modCount);
}
}

@Override
public void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
final int expectedModCount = modCount;
@SuppressWarnings("unchecked")
final E[] elementData = (E[]) this.elementData;
final int size = this.size;
for (int i=0; modCount == expectedModCount && i < size; i++) {
action.accept(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}

/**
* 在此列表中的元素上创建一个延迟绑定和故障快速分割器。
* Spliterator报告Spliterator. SIZED, Spliterator. SUBSIZED, and Spliterator.ORDERED。
* 覆盖实现应该记录额外特征值的报告。
*/
@Override
public Spliterator<E> spliterator() {
return new ArrayListSpliterator<>(this, 0, -1, 0);
}

/** Index-based split-by-two, lazily initialized Spliterator */
static final class ArrayListSpliterator<E> implements Spliterator<E> {
private final ArrayList<E> list;
private int index; // current index, modified on advance/split
private int fence; // -1 until used; then one past last index
private int expectedModCount; // initialized when fence set

/** Create new spliterator covering the given range */
ArrayListSpliterator(ArrayList<E> list, int origin, int fence,
int expectedModCount) {
this.list = list; // OK if null unless traversed
this.index = origin;
this.fence = fence;
this.expectedModCount = expectedModCount;
}

private int getFence() { // initialize fence to size on first use
int hi; // (a specialized variant appears in method forEach)
ArrayList<E> lst;
if ((hi = fence) < 0) {
if ((lst = list) == null)
hi = fence = 0;
else {
expectedModCount = lst.modCount;
hi = fence = lst.size;
}
}
return hi;
}

public ArrayListSpliterator<E> trySplit() {
int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
return (lo >= mid) ? null : // divide range in half unless too small
new ArrayListSpliterator<E>(list, lo, index = mid,
expectedModCount);
}

public boolean tryAdvance(Consumer<? super E> action) {
if (action == null)
throw new NullPointerException();
int hi = getFence(), i = index;
if (i < hi) {
index = i + 1;
@SuppressWarnings("unchecked") E e = (E)list.elementData[i];
action.accept(e);
if (list.modCount != expectedModCount)
throw new ConcurrentModificationException();
return true;
}
return false;
}

public void forEachRemaining(Consumer<? super E> action) {
int i, hi, mc; // hoist accesses and checks from loop
ArrayList<E> lst; Object[] a;
if (action == null)
throw new NullPointerException();
if ((lst = list) != null && (a = lst.elementData) != null) {
if ((hi = fence) < 0) {
mc = lst.modCount;
hi = lst.size;
}
else
mc = expectedModCount;
if ((i = index) >= 0 && (index = hi) <= a.length) {
for (; i < hi; ++i) {
@SuppressWarnings("unchecked") E e = (E) a[i];
action.accept(e);
}
if (lst.modCount == mc)
return;
}
}
throw new ConcurrentModificationException();
}

public long estimateSize() {
return (long) (getFence() - index);
}

public int characteristics() {
return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
}
}

@Override
public boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
// figure out which elements are to be removed
// any exception thrown from the filter predicate at this stage
// will leave the collection unmodified
int removeCount = 0;
final BitSet removeSet = new BitSet(size);
final int expectedModCount = modCount;
final int size = this.size;
for (int i=0; modCount == expectedModCount && i < size; i++) {
@SuppressWarnings("unchecked")
final E element = (E) elementData[i];
if (filter.test(element)) {
removeSet.set(i);
removeCount++;
}
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}

// shift surviving elements left over the spaces left by removed elements
final boolean anyToRemove = removeCount > 0;
if (anyToRemove) {
final int newSize = size - removeCount;
for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
i = removeSet.nextClearBit(i);
elementData[j] = elementData[i];
}
for (int k=newSize; k < size; k++) {
elementData[k] = null; // Let gc do its work
}
this.size = newSize;
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}

return anyToRemove;
}

@Override
@SuppressWarnings("unchecked")
public void replaceAll(UnaryOperator<E> operator) {
Objects.requireNonNull(operator);
final int expectedModCount = modCount;
final int size = this.size;
for (int i=0; modCount == expectedModCount && i < size; i++) {
elementData[i] = operator.apply((E) elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}

@Override
@SuppressWarnings("unchecked")
public void sort(Comparator<? super E> c) {
final int expectedModCount = modCount;
Arrays.sort((E[]) elementData, 0, size, c);
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
}