ArrayList 源码阅读笔记

目录

接口简介

主要继承和实现的类和接口
在这里插入图片描述

  • RandomAccess
    public interface RandomAccess
    Marker interface used by List implementations to indicate that they support fast (generally constant time) random access.
    大概意思是说 RandomAccess 是一个标志接口,表明实现这个接口的 List 集合支持快速随机访问。
    而且如果实现了 RandomAccess 接口,那么 List 集合使用 for 循环的方式获取数据会优于用迭代器的方式获取数据。

  • Cloneable
    Cloneable 是一个标记接口,只有实现这个接口,并且在类中重写 Object 类中的 clone() 方法,才能通过调用类 clone() 方法克隆成功。如果不实现这个接口,则会抛出 CloneNotSupportedException(克隆不被支持)异常。

  • Serializable
    Serializable 是一个标记接口,只有实现了这个接口才可以对对象进行序列化和反序列化

源码阅读

成员变量与构造函数

/**
 * The maximum size of array to allocate.
 * Some VMs reserve some header words in an array.
 * Attempts to allocate larger arrays may result in
 * OutOfMemoryError: Requested array size exceeds VM limit
 * 要分配的最大数组大小。 一些 VM 在阵列中保留一些标题字。 
 * 尝试分配更大的数组可能会导致 OutOfMemoryError:请求的数组大小超过VM限制
 */
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

/**
 * Default initial capacity.
 * 默认初始容量
 */
private static final int DEFAULT_CAPACITY = 10;

/**
 * Shared empty array instance used for empty instances.
 * 用于空实例的共享空数组实例。
 */
private static final Object[] EMPTY_ELEMENTDATA = {};

/**
 * Shared empty array instance used for default sized empty instances. We
 * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
 * first element is added.
 * 用于默认大小的空实例的共享空数组实例。 我们将此与EMPTY_ELEMENTDATA区分开来,
 * 以便在添加第一个元素时知道要膨胀多少。
 */
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

 /**
 * The array buffer into which the elements of the ArrayList are stored.
 * The capacity of the ArrayList is the length of this array buffer. Any
 * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
 * will be expanded to DEFAULT_CAPACITY when the first element is added.
 * 存储 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).
 * ArrayList 的大小(ArrayList 包含的元素数)
 */
private int size;

/**
 * The number of times this list has been <i>structurally modified</i>.
 * Structural modifications are those that change the size of the
 * list, or otherwise perturb it in such a fashion that iterations in
 * progress may yield incorrect results.
 * 此列表已被结构修改的次数。 结构修改是那些改变列表大小或以其他方式扰乱它的方式,
 * 即正在进行的迭代可能产生不正确的结果。
 * <p>This field is used by the iterator and list iterator implementation
 * returned by the {@code iterator} and {@code listIterator} methods.
 * If the value of this field changes unexpectedly, the iterator (or list
 * iterator) will throw a {@code ConcurrentModificationException} in
 * response to the {@code next}, {@code remove}, {@code previous},
 * {@code set} or {@code add} operations.  This provides
 * <i>fail-fast</i> behavior, rather than non-deterministic behavior in
 * the face of concurrent modification during iteration.
 * 该字段由{@code iterator}和{@code listIterator}方法返回的迭代器和列表迭代器实现使用。
 * 如果此字段的值意外更改,则迭代器(或列表迭代器)将抛出{@code ConcurrentModificationException}
 * 以响应{@code next},{@ code remove},{@ code previous},{@ code set }或{@code add}操作。 这提供了快速失败的行为,而不是在迭代期间面对并发修改时的非确定性行为。
 * <p><b>Use of this field by subclasses is optional.</b> If a subclass
 * wishes to provide fail-fast iterators (and list iterators), then it
 * merely has to increment this field in its {@code add(int, E)} and
 * {@code remove(int)} methods (and any other methods that it overrides
 * that result in structural modifications to the list).  A single call to
 * {@code add(int, E)} or {@code remove(int)} must add no more than
 * one to this field, or the iterators (and list iterators) will throw
 * bogus {@code ConcurrentModificationExceptions}.  If an implementation
 * does not wish to provide fail-fast iterators, this field may be
 * ignored.
 * 子类对子字段的使用是可选的。如果子类希望提供故障快速迭代器(和列表迭代器),那么它只需要在其{@code add(int,E)}
 * 和{@code remove中增加该字段(int)}方法(以及它覆盖的任何其他方法导致对列表进行结构修改)。 对{@code add(int,E)}
 * 或{@code remove(int)}的单个调用必须向此字段添加不超过一个,否则迭代器(和列表迭代器)将抛出伪造的{@code ConcurrentModificationExceptions}。
 * 如果实现不希望提供快速失败的迭代器,则可以忽略此字段。
 */
protected transient int modCount = 0;

/**
 * Constructs an empty list with the specified initial capacity.
 * 构造具有指定初始容量的空列表
 * @param  initialCapacity  the initial capacity of the list
 * List 初始容量
 * @throws IllegalArgumentException if the specified initial capacity
 *         is negative
 */
public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        // 根据 elementData 成员变量可知,ArrayList 内部存储数据是存到 Object 数组中
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        // 当初始容量为 0 时,使用 elementData = EMPTY_ELEMENTDATA 进行初始化
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    }
}

/**
 * Constructs an empty list with an initial capacity of ten.
 * 构造一个初始容量为 10 的空列表。
 */
public ArrayList() {
    // 无参构造使用 elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA 进行初始化
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

/**
 * Constructs a list containing the elements of the specified
 * collection, in the order they are returned by the collection's
 * iterator.
 * 按照集合的迭代器返回的顺序,构造一个包含指定集合元素的 List。
 * @param c the collection whose elements are to be placed into this list
 * 将其元素放入 List 的集合
 * @throws NullPointerException if the specified collection is null
 */
public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    if ((size = elementData.length) != 0) {
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        // c.toArray 可能(错误地)不返回 Object[]
        if (elementData.getClass() != Object[].class)
            // 将 elementDate 转换成 Object[] 数组
            // Arrays.copyOf() 将源数组拷贝一份指定类型的新数组,原有数组不变
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        // replace with empty array.
        // 有参构造使用 EMPTY_ELEMENTDATA 进行初始化
        this.elementData = EMPTY_ELEMENTDATA;
    }
}

说明

从构建 ArrayList 数组的构造函数上可以看出,使用无参构造时,使用的 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 作为引用,而使用 ArrayList 数组的有参构造时,使用的 EMPTY_ELEMENTDATA 作为应用的。这是 java 1.8 以后的代码这样使用的。

扩展方法源码

public ArrayList(int initialCapacity) {
    super();
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal Capacity: "+
                initialCapacity);
    this.elementData = new Object[initialCapacity];
}
 
public ArrayList() {
    super();
    this.elementData = EMPTY_ELEMENTDATA;
}
 
public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    size = elementData.length;
    // c.toArray might (incorrectly) not return Object[] (see 6260652)
    if (elementData.getClass() != Object[].class)
        elementData = Arrays.copyOf(elementData, size, Object[].class);
}

说明

以上可以看出完全就是 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 代替了 EMPTY_ELEMENTDATA。那 EMPTY_ELEMENTDATA 干什么去了?看一下构造函数中 EMPTY_ELEMENTDATA 安排在哪里了?都是在判断容量为空的情况下,赋值给 elementData。Java7 中如果容量是 0 的话,会创建一个空数组,赋值给 elementData。this.elementData = new Object[initialCapacity]; elementData = Arrays.copyOf(elementData, size, Object[].class);。如果一个应用中有很多这样 ArrayList 空实例的话,就会有很多的空数组,无疑 EMPTY_ELEMENTDATA 是为了优化性能,所有 ArrayList 空实例都指向同一个空数组。

trimToSize

/**
 * Trims the capacity of this <tt>ArrayList</tt> instance to be the
 * list's current size.  An application can use this operation to minimize
 * the storage of an <tt>ArrayList</tt> instance.
 * 将此 ArrayList 实例的容量调整为列表的当前大小。 
 * 应用程序可以使用此操作来最小化 ArrayList 实例的存储。
 */
public void trimToSize() {
    modCount++;
    if (size < elementData.length) {
        elementData = (size == 0)
          ? EMPTY_ELEMENTDATA
          : Arrays.copyOf(elementData, size);
    }
}

说明

trimToSize() 方法的功能就是去除多 ArrayList 余容量,使 elementData 数组缓冲区数组的大小等于时实际的 ArrayList 大小(size),ArrayList 的容量和大小(size)并不是一个概念。

  1. ArrayList 默认容量为 10 当填入 3 个元素时会用多余的容量
  2. ArrayLsit 动态增长为 旧容量 + 1/2 * 旧容量,填入的元素不满时会用多余容量产生;
  3. 删除 ArrayList 元素时,会产生多余容量。

扩展方法源码

// Arrays.copyOf(elementData, size, Object[].class)
/**
 * Copies the specified array, truncating or padding with nulls (if necessary)
 * so the copy has the specified length.  For all indices that are
 * valid in both the original array and the copy, the two arrays will
 * contain identical values.  For any indices that are valid in the
 * copy but not the original, the copy will contain <tt>null</tt>.
 * Such indices will exist if and only if the specified length
 * is greater than that of the original array.
 * The resulting array is of the class <tt>newType</tt>.
 *
 * 复制指定的数组, 如有必要用 null 截取或填充,以使副本具有指定的长度
 * 对于所有在原数组和副本中都有效的索引,这两个数组相同索引处将包含相同的值
 * 对于在副本中有效而在原数组无效的所有索引,副本将填充 null,当且仅当指定长度大于原数组的长度时,这些索引存在
 * 返回的数组属于 newType 类
 *
 * @param <U> the class of the objects in the original array
 * @param <T> the class of the objects in the returned array
 * @param original the array to be copied
 * @param newLength the length of the copy to be returned
 * @param newType the class of the copy to be returned
 * @return a copy of the original array, truncated or padded with nulls
 *     to obtain the specified length
 * 
 * @since 1.6
 */
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
    @SuppressWarnings("unchecked")
    // 如果新数组类型是 Object 数组类型(Object[].class),则 new Object 数组。
    // 否则利用 Java 的反射机制,通过数组的 Class 对象的 getComponentType() 方法可以取得一个数组的 Class 对象,
    // 通过 Array.newInstance() 可以反射生成数组对象。
    T[] copy = ((Object)newType == (Object)Object[].class)
        ? (T[]) new Object[newLength]
        : (T[]) Array.newInstance(newType.getComponentType(), newLength);
    // 将 original 数组的数据拷贝到新数组 copy 中
    System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
    return copy;
}

// System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength))
/**
 * src:源对象
 * srcPos:源数组中的起始位置
 * dest:目标数组对象
 * destPos:目标数据中的起始位置
 * length:要拷贝的数组元素的数量
 */
public static native void arraycopy(Object src,  int  srcPos,
                                    Object dest, int destPos,
                                    int length);

// (T[]) Array.newInstance(newType.getComponentType(), newLength)
/**
 * Creates a new array with the specified component type and
 * length.
 * Invoking this method is equivalent to creating an array
 * as follows:
 * <blockquote>
 * <pre>
 * int[] x = {length};
 * Array.newInstance(componentType, x);
 * </pre>
 * </blockquote>
 *
 * <p>The number of dimensions of the new array must not
 * exceed 255.
 *
 * @param componentType the {@code Class} object representing the
 * component type of the new array
 * @param length the length of the new array
 * @return the new array
 * @exception NullPointerException if the specified
 * {@code componentType} parameter is null
 * @exception IllegalArgumentException if componentType is {@link
 * Void#TYPE} or if the number of dimensions of the requested array
 * instance exceed 255.
 * @exception NegativeArraySizeException if the specified {@code length}
 * is negative
 */
public static Object newInstance(Class<?> componentType, int length)
    throws NegativeArraySizeException {
    return newArray(componentType, length);
}

// newArray(componentType, length)
private static native Object newArray(Class<?> componentType, int length)
    throws NegativeArraySizeException;

说明

在 Java 的反射机制中,通过 数组的 class 对象的 getComponentType() 方法可以取得一个数组的 Class 对象, 通过 Array.newInstance() 可以反射生成数组对象。

System.arrayCopy() 方法

  1. 首先对于一维数组,如果元素都是基础类型(如int,double等),使用arraycopy()方法后,是把原数组的值传给了新数组,属于值传递,故修改复制后的数组,原数组不受到影响。如果是不可变类如String,虽然属于引用传递,但是具有不可变的特征,故修改复制后的数组,原数组不受到影响。
  2. 对于二维数组,数组的第一维装的是一个一维数组的引用,第二维里是元素数值。对二维数组应用arraycopy()方法后,第一维的引用被复制给新数组的第一维,也就是两个数组的第一维都指向相同的“那些数组”。而这时改变其中任何一个数组的元素的值,其实都修改了“那些数组”的元素的值,所以原数组和新数组的元素值都一样了。

capacity

/**
 * Increases the capacity of this <tt>ArrayList</tt> instance, if
 * necessary, to ensure that it can hold at least the number of elements
 * specified by the minimum capacity argument.
 * 如有必要,增加此ArrayList实例的容量,以确保它至少可以容纳由 minimum capacity。
 * 等同于,指定 ArrayList 的最小容量。
 
 * (@param minCapacity) 参数指定的元素数。
 * @param   minCapacity   the desired minimum capacity
 */
public void ensureCapacity(int minCapacity) {
    //判断需要扩容的数组是否为空实例(空数组)如果为不为空,则变量等于0.为空则变量等于数组默认容量 10
    int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
        // any size if not default element table
        // 任何大小,如果不是默认元素表就返回 0
        ? 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 void ensureExplicitCapacity(int minCapacity) {
    // 修改次数 + 1
    modCount++;

    // overflow-conscious code
    // 对数组溢出进行考虑的代码 : 如果设置的最小容量大于缓存数组的大小会出现内存溢出
    if (minCapacity - elementData.length > 0)
        // 对 List 进行扩容
        grow(minCapacity);
}

/**
 * Checks if the given index is in range.  If not, throws an appropriate
 * runtime exception.  This method does *not* check if the index is
 * negative: It is always used immediately prior to an array access,
 * which throws an ArrayIndexOutOfBoundsException if index is negative.
 * 检查给定的索引是否在范围内。 如果不是,则抛出适当的运行时异常。 此方法不检查
 * 索引是否为负:始终在数组访问之前立即使用它,如果索引为负,则抛出
 * ArrayIndexOutOfBoundsException。
 */
private void rangeCheck(int index) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

/**
 * A version of rangeCheck used by add and addAll.
 * add 和addAll 使用的rangeCheck版本
 */
private void rangeCheckForAdd(int index) {
    if (index > size || index < 0)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

private static int calculateCapacity(Object[] elementData, int minCapacity) {
    // 如果 List 为空列表,返回默认容量和指定容量二者最大的值
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    // 如果 List 不为空列表,返回指定容量
    return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
    // 修改次数 + 1
    modCount++;

    // overflow-conscious code
    // 如果指定最小容量大于缓存数组的长度,对 List 进行扩容
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

/**
 * Increases the capacity to ensure that it can hold at least the
 * number of elements specified by the minimum capacity argument.
 * 增加容量以确保它至少可以容纳由minimum capacity参数指定的元素数。
 *
 * @param minCapacity the desired minimum capacity
 */
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    // 新容量 = 旧容量 + 旧容量的右移 1 位运算(旧容量一半)
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    // 若用户手动指定的最小扩容量大于了默认的扩容策略,则扩容量改为用户所指定的容量
    // 若用户手动指定的最小扩容量小于了默认的扩容策略,则使用默认扩容策略。
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    // 新容量大于数组的最大容量,就将新容量设置为最大容量(Integer.MAX_VALUE 或者 MAX_ARRAY_SIZE)    
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
}

/**
 * minCapacity 大于 MAX_ARRAY_SIZE 则返回整数类(Integer)的最大值(Integer.MAX_VALUE),
 * 否则返回数组的最大容量(MAX_ARRAY_SIZE) 
 */
private static int hugeCapacity(int minCapacity) {
    // 参数(最小容量)小于 0,抛出 OutOfMemoryError(内存溢出)
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    // 设置的最小容量大于数组的最大容量值则返回整数的最大值,否则返回数组的最大容量值为 ArrayList 的容量    
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}

contains

/**
 * Returns the element at the specified position in this list.
 * 返回此列表中指定位置的元素。
 * 
 * @param  index index of the element to return
 * @return the element at the specified position in this list
 * @throws IndexOutOfBoundsException {@inheritDoc}
 */
public E get(int index) {
    rangeCheck(index);

    return elementData(index);
}

/**
 * Returns the number of elements in this list.
 * 返回 List 中元素的个数
 
 * @return the number of elements in this list
 */
public int size() {
    return size;
}

/**
 * Returns <tt>true</tt> if this list contains no elements.
 * 如果 List 中没有包含元素,则返回 true
 
 * @return <tt>true</tt> if this list contains no elements
 */
public boolean isEmpty() {
    return size == 0;
}

/**
 * Returns <tt>true</tt> if this list contains the specified element.
 * More formally, returns <tt>true</tt> if and only if this list contains
 * at least one element <tt>e</tt> such that
 * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
 * 如果此列表包含指定的元素,则返回 true。 
 * 更正式地说,当且仅当此列表包含至少一个元素 e 时才返回 true  
 
 * @param o element whose presence in this list is to be tested
 * @return <tt>true</tt> if this list contains the specified element
 */
public boolean contains(Object o) {
    return indexOf(o) >= 0;
}

/**
 * Returns the index of the first occurrence of the specified element
 * in this list, or -1 if this list does not contain the element.
 * More formally, returns the lowest index <tt>i</tt> such that
 * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
 * or -1 if there is no such index.
 * 返回此列表中第一次出现的指定元素的索引,如果此列表不包含该元素,则返回 -1。
 * 更正式地说,如果元素存在则返回最低指数 i,否则返回 -1。就像这样
 * (o==null ? get(i)==null : o.equals(get(i)))
 */
public int indexOf(Object o) {
    // 在这里使用 for 循环遍历数实现查找效率最高,因为是对顺序数组使用快速随机访问
    // 这里分为两种情况:null 和 not null
    // 因为 o == null,使用方法 o.equals(elementData[i]]) 会抛出空指针异常
    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;
}

/**
 * Returns the index of the last occurrence of the specified element
 * in this list, or -1 if this list does not contain the element.
 * More formally, returns the highest index <tt>i</tt> such that
 * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
 * or -1 if there is no such index.
 * 返回指定元素在此列表中最后一次出现的索引;如果此列表不包含该元素,则返回-1。
 * 更正式地,返回最高索引 i,如果没有这样的索引返回 -1。就像这样 
 * (o==null ? get(i)==null : o.equals(get(i))) 
 */
public int lastIndexOf(Object o) {
    // 判断逻辑与 indexOf(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;
}

说明

为什么分为两种情况(null 和 not null)?

public static void main(String[] args) {

    // Obkect o
    String param = null;
    // elementData[i]
    String data = "ABC";

    // Result : false
    System.out.println(data == param);
    // Result : Exception in thread "main" java.lang.NullPointerException
    System.out.println(param.equals(data));
}

clone

/**
 * Returns a shallow copy of this <tt>ArrayList</tt> instance.  (The
 * elements themselves are not copied.)
 * 返回此 ArrayList 实例的浅表副本(浅克隆)。 (元素本身不会被复制。)
 * @return a clone of this <tt>ArrayList</tt> instance
 */
public Object clone() {
    try {
        // super.clone() 调用 Object 类的 clone() 方法(此方法是 C/C++ 所编写的本地方法)
        // 创建指定长度的某种类型的数组。
        ArrayList<?> v = (ArrayList<?>) super.clone();
        // 将 List 的缓存区数组数据拷贝到新创建 List 的缓存区数组中
        v.elementData = Arrays.copyOf(elementData, size);
        // 新 List 修改次数为 0
        v.modCount = 0;
        return v;
    } catch (CloneNotSupportedException e) {
        // this shouldn't happen, since we are Cloneable
        throw new InternalError(e);
    }
}

说明

浅拷贝:是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。

也就是说,在某些场景中,我们需要获取到一个对象的拷贝用于某些处理。这时候就可以用到 Java 中的 Object.clone 方法进行对象复制,得到一个一模一样的新对象。但是在实际使用过程中会发现:当对象中含有可变的引用类型属性时,在复制得到的新对象对该引用类型属性内容进行修改,原始对象响应的属性内容也会发生变化,这就是"浅拷贝"的现象。关于浅拷贝,Object.clone()方法的描述也有说明:

扩展方法源码

// (ArrayList<?>) super.clone()
/**
 * Creates and returns a copy of this object.  The precise meaning
 * of "copy" may depend on the class of the object. The general
 * intent is that, for any object {@code x}, the expression:
 * <blockquote>
 * <pre>
 * x.clone() != x</pre></blockquote>
 * will be true, and that the expression:
 * <blockquote>
 * <pre>
 * x.clone().getClass() == x.getClass()</pre></blockquote>
 * will be {@code true}, but these are not absolute requirements.
 * While it is typically the case that:
 * <blockquote>
 * <pre>
 * x.clone().equals(x)</pre></blockquote>
 * will be {@code true}, this is not an absolute requirement.
 * <p>
 * By convention, the returned object should be obtained by calling
 * {@code super.clone}.  If a class and all of its superclasses (except
 * {@code Object}) obey this convention, it will be the case that
 * {@code x.clone().getClass() == x.getClass()}.
 * <p>
 * By convention, the object returned by this method should be independent
 * of this object (which is being cloned).  To achieve this independence,
 * it may be necessary to modify one or more fields of the object returned
 * by {@code super.clone} before returning it.  Typically, this means
 * copying any mutable objects that comprise the internal "deep structure"
 * of the object being cloned and replacing the references to these
 * objects with references to the copies.  If a class contains only
 * primitive fields or references to immutable objects, then it is usually
 * the case that no fields in the object returned by {@code super.clone}
 * need to be modified.
 * <p>
 * The method {@code clone} for class {@code Object} performs a
 * specific cloning operation. First, if the class of this object does
 * not implement the interface {@code Cloneable}, then a
 * {@code CloneNotSupportedException} is thrown. Note that all arrays
 * are considered to implement the interface {@code Cloneable} and that
 * the return type of the {@code clone} method of an array type {@code T[]}
 * is {@code T[]} where T is any reference or primitive type.
 * Otherwise, this method creates a new instance of the class of this
 * object and initializes all its fields with exactly the contents of
 * the corresponding fields of this object, as if by assignment; the
 * contents of the fields are not themselves cloned. Thus, this method
 * performs a "shallow copy" of this object, not a "deep copy" operation.
 * <p>
 * The class {@code Object} does not itself implement the interface
 * {@code Cloneable}, so calling the {@code clone} method on an object
 * whose class is {@code Object} will result in throwing an
 * exception at run time.
 *
 * @return     a clone of this instance.
 * @throws  CloneNotSupportedException  if the object's class does not
 *               support the {@code Cloneable} interface. Subclasses
 *               that override the {@code clone} method can also
 *               throw this exception to indicate that an instance cannot
 *               be cloned.
 * @see java.lang.Cloneable
 */
protected native Object clone() throws CloneNotSupportedException;

说明

clone() 的用法与浅拷贝验证

public class Person implements Cloneable {
    private int age;
    private String name;
    private Address address;
    ...
}

public class Address {
    private String province;
    private String street;
    ...
}

public class Main {

    public static void main(String[] args) {

        ArrayList<Person> people = new ArrayList<>();

        people.add(new Person(12, "小明", new Address("北京", "回龙观")));

        // Person [age=12, name=小明, address=Address [province=北京, street=回龙观]]
        for (Person person: people) {
            System.out.println(person.display());
        }

        ArrayList<Person> clonePeople = (ArrayList<Person>) people.clone();
        
        // Person [age=12, name=小明, address=Address [province=北京, street=回龙观]]
        for (Person person: clonePeople) {
            System.out.println(person.display());
        }

        Person person = people.get(0);
        person.setAge(21);
        person.setName("张三");
        person.getAddress().setProvince("内蒙古");
        person.getAddress().setStreet("新华大街");

        people.set(0, person);
        
        // Person [age=21, name=张三, address=Address [province=内蒙古, street=新华大街]]
        for (Person p: people) {
            System.out.println(p.display());
        }

        // Person [age=21, name=张三, address=Address [province=内蒙古, street=新华大街]]
        for (Person p: clonePeople) {
            System.out.println(p.display());
        }

        Person person1 =  clonePeople.get(0);
        person1.setAge(18);
        person1.setName("李四");
        person1.getAddress().setProvince("江西");
        person1.getAddress().setStreet("凤凰大道");

        // Person [age=18, name=李四, address=Address [province=江西, street=凤凰大道]]
        for (Person p: people) {
            System.out.println(p.display());
        }

        // Person [age=18, name=李四, address=Address [province=江西, street=凤凰大道]]
        for (Person p: clonePeople) {
            System.out.println(p.display());
        }
    }
}

toArray

/**
 * Returns an array containing all of the elements in this list
 * in proper sequence (from first to last element).
 * 以正确的顺序(从第一个元素到最后一个元素)返回一个包含此列表中所有元素的数组。
 * <p>The returned array will be "safe" in that no references to it are
 * maintained by this list.  (In other words, this method must allocate
 * a new array).  The caller is thus free to modify the returned array.
 * 返回的数组将是“安全的”,因为此列表不保留对其的引用。 (换句话说,此方法必须分
 * 配一个新数组)。 因此,调用者可以自由修改返回的数组。
 * <p>This method acts as bridge between array-based and collection-based
 * APIs.
 * 此方法充当基于数组的 API 和基于集合的 API 之间的桥梁。
 *
 * @return an array containing all of the elements in this list in
 *         proper sequence
 */
public Object[] toArray() {
    return Arrays.copyOf(elementData, size);
}

/**
 * Returns an array containing all of the elements in this list in proper
 * sequence (from first to last element); the runtime type of the returned
 * array is that of the specified array.  If the list fits in the
 * specified array, it is returned therein.  Otherwise, a new array is
 * allocated with the runtime type of the specified array and the size of
 * this list.
 * 返回一个数组,该数组按适当顺序(从第一个元素到最后一个元素)包含此列表中的所
 * 有元素;返回数组的运行时类型是指定数组的运行时类型。 如果列表适合指定的数组,
 * 则将其返回。否则,将使用指定数组的运行时类型和此列表的大小分配一个新数组。
 * <p>If the list fits in the specified array with room to spare
 * (i.e., the array has more elements than the list), the element in
 * the array immediately following the end of the collection is set to
 * <tt>null</tt>.  (This is useful in determining the length of the
 * list <i>only</i> if the caller knows that the list does not contain
 * any null elements.)
 * 如果列表适合指定的数组并有剩余空间(即数组中的元素多于列表),则紧接集合结束后
 * 的数组中的元素设置为null。(如果调用方知道列表不包含任何null元素,则这对于确定
 * i 仅 i 列表的长度很有用。)
 *
 * @param a the array into which the elements of the list are to
 *          be stored, if it is big enough; otherwise, a new array of the
 *          same runtime type is allocated for this purpose.
 * @return an array containing the elements of the list
 * @throws ArrayStoreException if the runtime type of the specified array
 *         is not a supertype of the runtime type of every element in
 *         this list
 * @throws NullPointerException if the specified array is null
 */
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
    if (a.length < size)
        // Make a new array of a's runtime type, but my contents:
        return (T[]) Arrays.copyOf(elementData, size, a.getClass());
    System.arraycopy(elementData, 0, a, 0, size);
    if (a.length > size)
        a[size] = null;
    return a;
}

示例

public class Main {

    public static void main(String[] args) {

        ArrayList<Integer> array = new ArrayList();

        array.add(new Integer(1));
        array.add(new Integer(3));
        array.add(new Integer(5));
        array.add(new Integer(7));

        // 1357
        for (Integer integer: array)
            System.out.print(integer);
        System.out.println();

        Object[] a = array.toArray();

        // 1357
        for (int i = 0; i < 4; i++)
            System.out.print(((Integer) a[i]).intValue());
        System.out.println();

        a[2] = new Integer(10);

        // 1357
        for (Integer integer: array)
            System.out.print(integer);
        System.out.println();

        // 13107
        for (int i = 0; i < 4; i++)
            System.out.print(((Integer) a[i]).intValue());
        System.out.println();

        array.set(2, 100);

        // 131007
        for (Integer integer: array)
            System.out.print(integer);
        System.out.println();

        // 13107
        for (int i = 0; i < 4; i++)
            System.out.print(((Integer) a[i]).intValue());
    }
}
public class Main {

    public static void main(String[] args) {

        ArrayList<Person> people = new ArrayList<>();

        people.add(new Person(12, "小明", new Address("北京", "回龙观")));

        // Person [age=12, name=小明, address=Address [province=北京, street=回龙观]]
        for (Person person : people)
            System.out.println(person.display());

        Object[] arrayPeople = people.toArray();

        // Person [age=12, name=小明, address=Address [province=北京, street=回龙观]]
        for (Object object : arrayPeople)
            System.out.println(((Person) object).display());

        // true
        System.out.println(people.get(0) == (Person) arrayPeople[0]);

        Person person = people.get(0);
        person.setAge(21);
        person.setName("张三");
        person.getAddress().setProvince("内蒙古");
        person.getAddress().setStreet("新华大街");

        people.set(0, person);

        // Person [age=21, name=张三, address=Address [province=内蒙古, street=新华大街]]
        for (Person p : people)
            System.out.println(p.display());

        // Person [age=21, name=张三, address=Address [province=内蒙古, street=新华大街]]
        for (Object object : arrayPeople)
            System.out.println(((Person) object).display());

        // true
        System.out.println(people.get(0) == (Person) arrayPeople[0]);

        Person person1 =  (Person) arrayPeople[0];
        person1.setAge(18);
        person1.setName("李四");
        person1.getAddress().setProvince("江西");
        person1.getAddress().setStreet("凤凰大道");

        // Person [age=18, name=李四, address=Address [province=江西, street=凤凰大道]]
        for (Person p: people)
            System.out.println(p.display());

        // Person [age=18, name=李四, address=Address [province=江西, street=凤凰大道]]
        for (Object object : arrayPeople)
            System.out.println(((Person) object).display());

        // true
        System.out.println(people.get(0) == (Person) arrayPeople[0]);
    }
}

add

/**
 * Replaces the element at the specified position in this list with
 * the specified element.
 * 用指定元素替换此列表中指定位置的元素,并返回就旧元素
 *
 * @param index index of the element to replace
 * @param element element to be stored at the specified position
 * @return the element previously at the specified position
 * @throws IndexOutOfBoundsException {@inheritDoc}
 */
public E set(int index, E element) {
    rangeCheck(index);

    E oldValue = elementData(index);
    elementData[index] = element;
    return oldValue;
}

/**
 * Appends the specified element to the end of this list.
 * 将指定的元素追加到此列表的末尾。
 *
 * @param e element to be appended to this list
 * @return <tt>true</tt> (as specified by {@link Collection#add})
 */
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

/**
 * Inserts the specified element at the specified position in this
 * list. Shifts the element currently at that position (if any) and
 * any subsequent elements to the right (adds one to their indices).
 *
 * @param index index at which the specified element is to be inserted
 * @param element element to be inserted
 * @throws IndexOutOfBoundsException {@inheritDoc}
 */
public void add(int index, E element) {
    rangeCheckForAdd(index);

    ensureCapacityInternal(size + 1);  // Increments modCount!!
    // 将内部缓存数组从 index 向后移一位
    // index -- size - 1  拷贝到 index + 1 -- size
    System.arraycopy(elementData, index, elementData, index + 1,
                     size - index);
    // 对 index 位置进行辅助,实现插入                 
    elementData[index] = element;
    size++;
}

/**
 * Appends all of the elements in the specified collection to the end of
 * this list, in the order that they are returned by the
 * specified collection's Iterator.  The behavior of this operation is
 * undefined if the specified collection is modified while the operation
 * is in progress.  (This implies that the behavior of this call is
 * undefined if the specified collection is this list, and this
 * list is nonempty.)
 * 按照指定集合的 Iterator 返回的顺序,将指定集合中的所有元素追加到此列表的末尾。
 * 如果在操作进行过程中修改了指定的集合,则此操作的行为是不确定的。(这意味着如
 * 果指定的集合是此列表,并且此列表是非空的,则此调用的行为是不确定的。)
 * 也就是说:非线程安全,在插入的过程中改变 List 元素,将得到改变之后的元素
 * 
 * @param c collection containing elements to be added to this list
 * @return <tt>true</tt> if this list changed as a result of the call
 * @throws NullPointerException if the specified collection is null
 */
public boolean addAll(Collection<? extends E> c) {
    // 将 List 转换为 Array
    Object[] a = c.toArray();
    // 获取新增元素个数
    int numNew = a.length;
    ensureCapacityInternal(size + numNew);  // Increments modCount : 确认是否需要扩容
    // 将 a 数组中的元素复制到 Lsit 缓存数组尾部
    System.arraycopy(a, 0, elementData, size, numNew);
    // List size 更新
    size += numNew;
    // 返回是否添加新元素
    return numNew != 0;
}

/**
 * Inserts all of the elements in the specified collection into this
 * list, starting at the specified position.  Shifts the element
 * currently at that position (if any) and any subsequent elements to
 * the right (increases their indices).  The new elements will appear
 * in the list in the order that they are returned by the
 * specified collection's iterator.
 * 从指定位置开始,将指定集合中的所有元素插入此列表。 将当前位于该位置的元素
 * (如果有)和任何后续元素右移(增加其索引)。新元素将按照指定集合的迭代器返
 * 回的顺序显示在列表中。
 *
 * @param index index at which to insert the first element from the
 *              specified collection
 * @param c collection containing elements to be added to this list
 * @return <tt>true</tt> if this list changed as a result of the call
 * @throws IndexOutOfBoundsException {@inheritDoc}
 * @throws NullPointerException if the specified collection is null
 */
public boolean addAll(int index, Collection<? extends E> c) {
    // 边界检查
    rangeCheckForAdd(index);
    
    // 将 List 转换为 Array
    Object[] a = c.toArray();
    // 获取新增元素个数
    int numNew = a.length;
    ensureCapacityInternal(size + numNew);  // Increments modCount : 确认是否需要扩容

    // 获取移动的元素个数
    int numMoved = size - index;
    if (numMoved > 0)
        // 实现将 List 后移 numMoved 位
        System.arraycopy(elementData, index, elementData, index + numNew,
                         numMoved);
    
    // 将新增数组元素插入到指定位置
    System.arraycopy(a, 0, elementData, index, numNew);
    // List size 更新
    size += numNew;
    return numNew != 0;
}

remove

/**
 * Removes the element at the specified position in this list.
 * Shifts any subsequent elements to the left (subtracts one from their
 * indices).
 * 删除此列表中指定位置的元素。 将所有后续元素向左移动(从其索引中减去一个)。
 *
 * @param index the index of the element to be removed
 * @return the element that was removed from the list
 * @throws IndexOutOfBoundsException {@inheritDoc}
 */
public E remove(int index) {
    rangeCheck(index);

    modCount++;
    E oldValue = elementData(index);
    
    // 计算要移动的元素数量
    int numMoved = size - index - 1;
    if (numMoved > 0)
        // 实现 index 之后的元素(从 index + 1 开始)向前移一位
        // index + 1 -- size -1  拷贝到 index -- size - 2
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    // 将最后一位元素置为 null                     
    elementData[--size] = null; // clear to let GC do its work : 置空原尾部数据不再强引用,可以 GC 掉

    return oldValue;
}

/**
 * Removes the first occurrence of the specified element from this list,
 * if it is present.  If the list does not contain the element, it is
 * unchanged.  More formally, removes the element with the lowest index
 * <tt>i</tt> such that
 * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>
 * (if such an element exists).  Returns <tt>true</tt> if this list
 * contained the specified element (or equivalently, if this list
 * changed as a result of the call).
 *
 * @param o element to be removed from this list, if present
 * @return <tt>true</tt> if this list contained the specified element
 */
public boolean remove(Object o) {
    // 与 indexOf() 方法逻辑相似
    // 分为 null 和 not null 两种情况,避免 equals() 方法抛出空指针异常
    if (o == null) {
        for (int index = 0; index < size; index++)
            if (elementData[index] == null) {
                // 快速移除方法(逻辑就是 remove(int index) 方法的逻辑)
                fastRemove(index);
                return true;
            }
    } else {
        for (int index = 0; index < size; index++)
            if (o.equals(elementData[index])) {
                fastRemove(index);
                return true;
            }
    }
    return false;
}

/*
 * Private remove method that skips bounds checking and does not
 * return the value removed.
 * 私有remove 方法,跳过边界检查并且不返回已删除的值。
 */
private void fastRemove(int index) {
    modCount++;
    // 逻辑与 remove(int 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 : 置空原尾部数据不再强引用,可以 GC 掉
}

/**
 * Removes from this list all of the elements whose index is between
 * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
 * Shifts any succeeding elements to the left (reduces their index).
 * This call shortens the list by {@code (toIndex - fromIndex)} elements.
 * (If {@code toIndex==fromIndex}, this operation has no effect.)
 * 从此列表中删除索引在{@code fromIndex}(包括)和{@code toIndex}(不包括)
 * 之间的所有元素。将所有后续元素向左移动(减少其索引)。此调用通过
 * {@code(toIndex-fromIndex)}元素来缩短列表。(如果{@code toIndex == fromIndex},则此操作无效。)
 *
 * @throws IndexOutOfBoundsException if {@code fromIndex} or
 *         {@code toIndex} is out of range
 *         ({@code fromIndex < 0 ||
 *          fromIndex >= size() ||
 *          toIndex > size() ||
 *          toIndex < fromIndex})
 */
protected void removeRange(int fromIndex, int toIndex) {
    modCount++;
    // 获取要移动的元素个数
    int numMoved = size - toIndex;
    // 实现将缓存数组 toIndex 之后的元素整体移到 fromIndex 之后的系列位置
    System.arraycopy(elementData, toIndex, elementData, fromIndex,
                     numMoved);

    // clear to let GC do its work : 置空原尾部数据不再强引用,可以 GC 掉
    // 获取移除指定元素之后的数组大小
    int newSize = size - (toIndex-fromIndex);
    // 将多余元素置 null
    for (int i = newSize; i < size; i++) {
        elementData[i] = null;
    }
    // List size 更新
    size = newSize;
}

/**
 * Removes all of the elements from this list.  The list will
 * be empty after this call returns.
 * 从此列表中删除所有元素。此调用返回后,列表将为空。
 */
public void clear() {
    modCount++;

    // clear to let GC do its work : 置空原尾部数据不再强引用,可以 GC 掉
    for (int i = 0; i < size; i++)
        elementData[i] = null;

    size = 0;
}

/**
 * Removes from this list all of its elements that are contained in the
 * specified collection.
 * 从此列表中移除指定集合中包含的所有其元素。
 *
 * @param c collection containing elements to be removed from this list
 * @return {@code true} if this list changed as a result of the call
 * @throws ClassCastException if the class of an element of this list
 *         is incompatible with the specified collection
 * (<a href="Collection.html#optional-restrictions">optional</a>)
 * @throws NullPointerException if this list contains a null element and the
 *         specified collection does not permit null elements
 * (<a href="Collection.html#optional-restrictions">optional</a>),
 *         or if the specified collection is null
 * @see Collection#contains(Object)
 */
public boolean removeAll(Collection<?> c) {
    // 参数非 null 验证
    Objects.requireNonNull(c);
    return batchRemove(c, false);
}

/**
 * Retains only the elements in this list that are contained in the
 * specified collection.  In other words, removes from this list all
 * of its elements that are not contained in the specified collection.
 * 仅保留此列表中包含在指定集合中的元素。换句话说,从该列表中删除所有未包含在指定集合中的元素。
 *
 * @param c collection containing elements to be retained in this list
 * @return {@code true} if this list changed as a result of the call
 * @throws ClassCastException if the class of an element of this list
 *         is incompatible with the specified collection
 * (<a href="Collection.html#optional-restrictions">optional</a>)
 * @throws NullPointerException if this list contains a null element and the
 *         specified collection does not permit null elements
 * (<a href="Collection.html#optional-restrictions">optional</a>),
 *         or if the specified collection is null
 * @see Collection#contains(Object)
 */
public boolean retainAll(Collection<?> c) {
    // 参数非 null 验证
    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 {
        // 循环遍历 List,并检查这个集合是否包含对应的值,移动要保留的值到数组前面,w 是最后要保留的元素数量
        // 也就是说:若保留,就将相同元素向前移动;若删除,就将不同元素向前移动
        for (; r < size; r++)
            // 判断 c 中是否包含 List 中的元素,并根据 complement 参数决定是参数还是保留
            if (c.contains(elementData[r]) == complement)
                elementData[w++] = elementData[r];
    } finally {
        // Preserve behavioral compatibility with AbstractCollection, even if c.contains() throws.
        // 即使c.contains()抛出异常,仍保留与 AbstractCollection 的行为兼容性。
        // 也就是说:r != size 表示可能出错了,c.contains() 抛出异常
        if (r != size) {
            System.arraycopy(elementData, r, elementData, w, size - r);
            w += size - r;
        }
        // 如果 w == size 表示元素全部保留了,没有删除操作发生,返回 modified = false;反之返回 true,并更改数组
        // 如果 w != size 即使 try 块抛出异常,也能正确异常处理抛出前的操作,因为 w 始终为要保留的前段部分,数组也不会因此乱序
        if (w != size) {
            // clear to let GC do its work : 置空原尾部数据不再强引用,可以 GC 掉
            for (int i = w; i < size; i++)
                elementData[i] = null;
            // 改变的次数    
            modCount += size - w;
            // List 的大小为保留元素的个数
            size = w;
            modified = true;
        }
    }
    return modified;
}

/**
 * Checks if the given index is in range.  If not, throws an appropriate
 * runtime exception.  This method does *not* check if the index is
 * negative: It is always used immediately prior to an array access,
 * which throws an ArrayIndexOutOfBoundsException if index is negative.
 * 检查给定的索引是否在范围内。 如果不是,则抛出适当的运行时异常。 此方法不检查
 * 索引是否为负:始终在数组访问之前立即使用它,如果索引为负,则抛出
 * ArrayIndexOutOfBoundsException。
 */
private void rangeCheck(int index) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

扩展方法源码

/**
 * Checks that the specified object reference is not {@code null}. This
 * method is designed primarily for doing parameter validation in methods
 * and constructors, as demonstrated below:
 * <blockquote><pre>
 * public Foo(Bar bar) {
       // 参数非 null 验证
 *     this.bar = Objects.requireNonNull(bar);
 * }
 * </pre></blockquote>
 * 检查指定的对象引用不是{@code null}。此方法主要用于在方法和构造函数中进行参数验证
 *
 * @param obj the object reference to check for nullity
 * @param <T> the type of the reference
 * @return {@code obj} if not {@code null}
 * @throws NullPointerException if {@code obj} is {@code null}
 */
public static <T> T requireNonNull(T obj) {
    if (obj == null)
        throw new NullPointerException();
    return obj;
}

serialize

/**
 * Save the state of the <tt>ArrayList</tt> instance to a stream (that
 * is, serialize it).
 * 将 ArrayList 实例的状态保存到流中(即,对其进行序列化)。
 *
 * @serialData The length of the array backing the <tt>ArrayList</tt>
 *             instance is emitted (int), followed by all of its elements
 *             (each an <tt>Object</tt>) in the proper order.
 *
* @param  java.io.ObjectOutputStream  是实现序列化的关键类,它可以将一个对象转换成
* 二进制流,然后可以通过 ObjectInputStream 将二进制流还原成对象
*/
 // java.io.ObjectOutputStream 是实现序列化的关键类,它可以将一个对象转换成二进制流,
 // 然后可以通过 ObjectInputStream 将二进制流还原成对象。
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()
    // 写出 size 作为与 clone() 方法兼容的容量
    s.writeInt(size);

    // Write out all elements in the proper order.
    // 按照正确的顺序序列化写出所有元素序。
    for (int i=0; i<size; i++) {
        s.writeObject(elementData[i]);
    }
    
    // 如果 List 修改次数和预期修改次数不一致,抛出 ConcurrentModificationException 异常
    // 也就是说,在进行序列化的过程中修改了 Lsit 将序列化失败
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
}

/**
 * Reconstitute the <tt>ArrayList</tt> instance from a stream (that is,
 * deserialize it).
 * 从流中重构 ArrayList 实例(即,将其反序列化)。
 */
private void readObject(java.io.ObjectInputStream s)
    throws java.io.IOException, ClassNotFoundException {
    elementData = EMPTY_ELEMENTDATA;

    // Read in size, and any hidden stuff
    // 读出 size 以及任何隐藏的内容
    s.defaultReadObject();

    // Read in capacity
    // 读入容量
    s.readInt(); // ignored

    if (size > 0) {
        // be like clone(), allocate array based upon size not capacity
        // 像clone()一样,根据大小而不是容量分配数组
        // 计算缓存数组容量
        int capacity = calculateCapacity(elementData, size);
        SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, capacity);
        // 按照 size 的大小对 List 进行扩容
        ensureCapacityInternal(size);

        // 因为 elementData 是 transient 修饰,所以不能够序列化。因此把 elementData 
        // 引用复制给 a(也就是说 a 和 elementData 指向同一个数组地址),向 a 中写元素
        // 就是向 elementData 中写入元素
        Object[] a = elementData;
        // Read in all elements in the proper order.
        // 按正确的顺序读入所有元素。
        for (int i=0; i<size; i++) {
            a[i] = s.readObject();
        }
    }
}

说明

s.readInt(); // ignored中 s.readInt() 不能删,不然 writeobject 写入的 size 数据会被读到 a[] 数组中造成数据错位,会造成写入流读取不全,抛出 IllegalStateException。writeobject 和 readobject 中数据流读写要对等,也就是写多少读多少。而且试着去掉了 s.writeInt(size), ArrayList是可以正常工作的(s.readInt()也要同时删除,保持数据对等),s.writeInt(size) 猜测是为了向前兼容,s.readInt()是因 s.writeInt(size) 存在而存在的,这里读了 size 数据却忽视这个数据不用它,s.readInt()纯粹是为了跳过 size 这个数据读取 elemendata 数据到 a 数组中。

扩展方法源码

// public class ObjectOutputStream

/** filter stream for handling block data conversion */
private final BlockDataOutputStream bout;

// values below valid only during upcalls to writeObject()/writeExternal()
/**
 * Context during upcalls to class-defined writeObject methods; holds
 * object currently being serialized and descriptor for current class.
 * Null when not during writeObject upcall.
 * 在类定义的 writeObject 方法的上调期间的上下文;保存当前正在序列化的对象和当前类的描述符。
 * 在未调用 writeObject 时为 null。
 */
private SerialCallbackContext curContext;

/** filter stream for handling block data conversion */
// 过滤流,用于处理块数据转换
private final BlockDataOutputStream bout;

// s.defaultWriteObject()
/**
 * Write the non-static and non-transient fields of the current class to
 * this stream.  This may only be called from the writeObject method of the
 * class being serialized. It will throw the NotActiveException if it is
 * called otherwise.
 * 将当前类的非静态和非瞬态字段写入此流。只能从要序列化的类的 writeObject 方法中调用此方法。
 * 如果否则调用它将抛出 NotActiveException。
 *
 * @throws  IOException if I/O errors occur while writing to the underlying
 *          <code>OutputStream</code>
 */
public void defaultWriteObject() throws IOException {
    SerialCallbackContext ctx = curContext;
    if (ctx == null) {
        throw new NotActiveException("not in call to writeObject");
    }
    Object curObj = ctx.getObj();
    ObjectStreamClass curDesc = ctx.getDesc();
    bout.setBlockDataMode(false);
    defaultWriteFields(curObj, curDesc);
    bout.setBlockDataMode(true);
}

/**
 * Write the specified object to the ObjectOutputStream.  The class of the
 * object, the signature of the class, and the values of the non-transient
 * and non-static fields of the class and all of its supertypes are
 * written.  Default serialization for a class can be overridden using the
 * writeObject and the readObject methods.  Objects referenced by this
 * object are written transitively so that a complete equivalent graph of
 * objects can be reconstructed by an ObjectInputStream.
 * 将指定的对象写入 ObjectOutputStream。写入对象的类,类的签名以及该类及其所有超
 * 类型的非瞬态和非静态字段的值。可以使用 writeObject和readObject 方法覆盖类的默
 * 认序列化。可以使用 writeObject 和 readObject 方法覆盖类的默认序列化。
 * 
 * <p>Exceptions are thrown for problems with the OutputStream and for
 * classes that should not be serialized.  All exceptions are fatal to the
 * OutputStream, which is left in an indeterminate state, and it is up to
 * the caller to ignore or recover the stream state.
 * 对于 OutputStream 的问题和不应序列化的类,将引发异常。所有异常对于OutputStream
 * 都是致命的,OutputStream 处于不确定状态,并且取决于调用者忽略还是恢复流状态。
 *
 * @throws  InvalidClassException Something is wrong with a class used by
 *          serialization.
 * @throws  NotSerializableException Some object to be serialized does not
 *          implement the java.io.Serializable interface.
 * @throws  IOException Any exception thrown by the underlying
 *          OutputStream.
 */
public final void writeObject(Object obj) throws IOException {
    if (enableOverride) {
        writeObjectOverride(obj);
        return;
    }
    try {
        writeObject0(obj, false);
    } catch (IOException ex) {
        if (depth == 0) {
            writeFatalException(ex);
        }
        throw ex;
    }
}

// s.writeInt(size)
/**
 * Writes a 32 bit int.
 *
 * @param   val the integer value to be written
 * @throws  IOException if I/O errors occur while writing to the underlying
 *          stream
 */
public void writeInt(int val)  throws IOException {
    bout.writeInt(val);
}

// public class ObjectInputStream

/**
 * Read the non-static and non-transient fields of the current class from
 * this stream.  This may only be called from the readObject method of the
 * class being deserialized. It will throw the NotActiveException if it is
 * called otherwise.
 * 从此流中读取当前类的非静态和非瞬态字段。 只能从要反序列化的类的 readObject 方法
 * 中调用此方法。如果否则调用它将抛出 NotActiveException。
 *
 * @throws  ClassNotFoundException if the class of a serialized object
 *          could not be found.
 * @throws  IOException if an I/O error occurs.
 * @throws  NotActiveException if the stream is not currently reading
 *          objects.
 */
public void defaultReadObject()
    throws IOException, ClassNotFoundException
{
    SerialCallbackContext ctx = curContext;
    if (ctx == null) {
        throw new NotActiveException("not in call to readObject");
    }
    Object curObj = ctx.getObj();
    ObjectStreamClass curDesc = ctx.getDesc();
    bin.setBlockDataMode(false);
    defaultReadFields(curObj, curDesc);
    bin.setBlockDataMode(true);
    if (!curDesc.hasWriteObjectData()) {
        /*
         * Fix for 4360508: since stream does not contain terminating
         * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere
         * knows to simulate end-of-custom-data behavior.
         */
        defaultDataEnd = true;
    }
    ClassNotFoundException ex = handles.lookupException(passHandle);
    if (ex != null) {
        throw ex;
    }
}

/**
 * Reads a 32 bit int.
 *
 * @return  the 32 bit integer read.
 * @throws  EOFException If end of file is reached.
 * @throws  IOException If other I/O error has occurred.
 */
public int readInt()  throws IOException {
    return bin.readInt();
}

/**
 * Read an object from the ObjectInputStream.  The class of the object, the
 * signature of the class, and the values of the non-transient and
 * non-static fields of the class and all of its supertypes are read.
 * Default deserializing for a class can be overridden using the writeObject
 * and readObject methods.  Objects referenced by this object are read
 * transitively so that a complete equivalent graph of objects is
 * reconstructed by readObject.
 * 从 ObjectInputStream 读取一个对象。读取对象的类,类的签名以及该类及其所有超类型
 * 的非瞬态和非静态字段的值。可以使用 writeObject 和 readObject 方法覆盖类的默认反
 * 序列化。该对象引用的对象是可传递的,因此 readObject 可以重建对象的完整等效图。
 * <p>The root object is completely restored when all of its fields and the
 * objects it references are completely restored.  At this point the object
 * validation callbacks are executed in order based on their registered
 * priorities. The callbacks are registered by objects (in the readObject
 * special methods) as they are individually restored.
 * 根对象的所有字段及其引用的对象都完全还原后,根对象将完全还原。此时,对象验证回调
 * 将根据其注册优先级按顺序执行。回调是由对象注册的(在 readObject 特殊方法中),因为
 * 它们分别进行了恢复。
 * <p>Exceptions are thrown for problems with the InputStream and for
 * classes that should not be deserialized.  All exceptions are fatal to
 * the InputStream and leave it in an indeterminate state; it is up to the
 * caller to ignore or recover the stream state.
 * 对于 InputStream 的问题和不应反序列化的类,将引发异常。所有异常对 InputStream 都是
 * 致命的,并使其处于不确定状态;调用者可以忽略或恢复流状态。
 *
 * @throws  ClassNotFoundException Class of a serialized object cannot be
 *          found.
 * @throws  InvalidClassException Something is wrong with a class used by
 *          serialization.
 * @throws  StreamCorruptedException Control information in the
 *          stream is inconsistent.
 * @throws  OptionalDataException Primitive data was found in the
 *          stream instead of objects.
 * @throws  IOException Any of the usual Input/Output related exceptions.
 */
public final Object readObject()
    throws IOException, ClassNotFoundException
{
    if (enableOverride) {
        return readObjectOverride();
    }

    // if nested read, passHandle contains handle of enclosing object
    int outerHandle = passHandle;
    try {
        Object obj = readObject0(false);
        handles.markDependency(outerHandle, passHandle);
        ClassNotFoundException ex = handles.lookupException(passHandle);
        if (ex != null) {
            throw ex;
        }
        if (depth == 0) {
            vlist.doCallbacks();
        }
        return obj;
    } finally {
        passHandle = outerHandle;
        if (closed && depth == 0) {
            clear();
        }
    }
}

iterator

/**
 * Returns a list iterator over the elements in this list (in proper
 * sequence), starting at the specified position in the list.
 * The specified index indicates the first element that would be
 * returned by an initial call to {@link ListIterator#next next}.
 * An initial call to {@link ListIterator#previous previous} would
 * return the element with the specified index minus one.
 * 从列表中的指定位置开始,以适当的顺序返回在此列表中的元素上的列表迭代器。指定的
 * 索引指示初始调用 {@link ListIterator#next next} 将返回的第一个元素。初次
* 调用 {@link ListIterator#previous previous} 将返回具有指定索引减一的元素。
* <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
* 返回的列表迭代器是 fail-fast
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public ListIterator<E> listIterator(int index) {
    if (index < 0 || index > size)
        throw new IndexOutOfBoundsException("Index: "+index);
    return new ListItr(index);
}

/**
 * Returns a list iterator over the elements in this list (in proper
 * sequence).
 * 返回此列表中的元素的列表迭代器(按适当顺序)。
 * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
 * 返回的列表迭代器是 fail-fast
 * 
 * @see #listIterator(int)
 */
public ListIterator<E> listIterator() {
    return new ListItr(0);
}

/**
 * Returns an iterator over the elements in this list in proper sequence.
 * 以正确的顺序返回此列表中元素的迭代器。
 * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
 * 返回的列表迭代器是 fail-fast
 *
 * @return an iterator over the elements in this list in proper sequence
 */
public Iterator<E> iterator() {
    return new Itr();
}

/**
 * An optimized version of AbstractList.Itr
 */
private class Itr implements Iterator<E> {
    // index of next element to return : 下一个要返回的元素的索引
    int cursor;      
    // index of last element returned; -1 if no such : 返回的最后一个元素的索引; -1(如果没有)
    // 返回的最后一个元素不是 List 最后一个元素,而是最后异常通过 next 和 pervious 获得的元素
    int lastRet = -1; 
    int expectedModCount = modCount;

    Itr() {}

    // 下一个索引 != seize 说明还存在下一个元素
    public boolean hasNext() {
        return cursor != size;
    }

    @SuppressWarnings("unchecked")
    public E next() {
        // 检查 List 是否在操作期间被修改 
        checkForComodification();
        // 当前要操作元素的索引
        int i = cursor;
        // 判断当前索引是否越界
        if (i >= size)
            throw new NoSuchElementException();
        // 获取 List 缓存数组,目的是避免一次无意义的寻址
        Object[] elementData = ArrayList.this.elementData;
        // 判断当前索引是否越界,防止 size 和 elementData.length 不一致的情况
        if (i >= elementData.length)
            throw new ConcurrentModificationException();
        // 获得下一个元素索引
        cursor = i + 1;
        // 返回当前索引下的元素,并将当前索引复制给 lastRet
        return (E) elementData[lastRet = i];
    }
    
    // remove 必须要跟在 next() 或是 previous()之后,而且只能执行一次,删多个元素,
    // 需要再执行 next() 或 previous()。在执行 next() 或 previous() 后不能先执行了 
    // add() 方法。因为 add() 方法执行以后,迭代器已经移动了,这样所要删除的目标元素
    // 指向不明,会报异常。
    public void remove() {
        if (lastRet < 0)
            throw new IllegalStateException();
        // 检查 List 是否在操作期间被修改 
        checkForComodification();

        try {
            // 调用 ArrayList 的 remove 方法
            ArrayList.this.remove(lastRet);
            // 将最后获取的索引复制给下一个索引
            cursor = lastRet;
            // 这里 lastRet = -1(< 0),方法开始就已经进行了限制 < 0 抛出异常。
            // 这就是为什么 remove 只能跟在 next 和 previous 后面的原因
            lastRet = -1;
            expectedModCount = modCount;
        } catch (IndexOutOfBoundsException ex) {
            throw new ConcurrentModificationException();
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    // forEachRemaining() 是 Iterator 接口在 1.8 的时候引入的一个默认方法
    // 为每个剩余元素执行给定的操作,直到所有的元素都已经被处理或行动将抛出一个异常
    // Consumer 消费者类
    public void forEachRemaining(Consumer<? super E> consumer) {
        // 参数非 null 验证
        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();
        }
        // 遍历对 Lsit 中剩余(cursor 索引开始)部分进行 consumer.accept 操作
        while (i != size && modCount == expectedModCount) {
            // accept() 接受并改变某个对象的内部值
            consumer.accept((E) elementData[i++]);
        }
        // update once at end of iteration to reduce heap write traffic
        // 在迭代结束时更新一次,以减少堆写入流量
        // while 循环中 i++ 会造成 i = size结果
        cursor = i;
        lastRet = i - 1;
        checkForComodification();
    }

    // 检查 List 修改次数与预期修改次数是否一致,多用于多线程的情景
    final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
}

/**
 * An optimized version of AbstractList.ListItr
 * 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() {
        // 检查 List 是否在操作期间被修改
        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;
        // 更新最后所获取元素的索引 lastRet
        return (E) elementData[lastRet = i];
    }

    public void set(E e) {
        // 如果不存在最后一次操作元素
        if (lastRet < 0)
            throw new IllegalStateException();
        checkForComodification();

        try {
            // 调用 List 的 set 方法进行赋值
            ArrayList.this.set(lastRet, e);
        } catch (IndexOutOfBoundsException ex) {
            throw new ConcurrentModificationException();
        }
    }

    public void add(E e) {
        // 检查 List 是否在操作期间被修改
        checkForComodification();

        try {
            // 当前要操作元素的索引
            int i = cursor;
            // 调用 List add 方法进行数据插入
            ArrayList.this.add(i, e);
            // 下一个元素索引 + 1,也就是说下次获取的元素并不是新增的元素
            cursor = i + 1;
            lastRet = -1;
            // 更新预期修改次数,因为 List add 方法对 modCount + 1
            expectedModCount = modCount;
        } catch (IndexOutOfBoundsException ex) {
            throw new ConcurrentModificationException();
        }
    }
}

说明

ArrayList 源码中实现 Iterator 接口中的 next() 方法时,为什么定义 Object[] elementData = ArrayList.this.elementData,然后从定义的 elementData 数组上取值。return (E) elementData[lastRet = i]。而不是直接使用 ArrayList.this.elementData[lastRet = i]?

// 如果写成如下形式,那么程序会多一次不必要的寻址。
if (i >= ArrayList.this.elementData.length)
    throw new ConcurrentModificationException();
cursor = i + 1;
return (E) ArrayList.this.elementData[lastRet = i];

Iterator 只能单向移动。
Iterator.remove()唯一安全的方式来在迭代过程中修改集合;如果在迭代过程中以任何其它的方式修改了基本集合将会产生未知的行为。而且每调用一次 next() 方法,remove()方法只能被调用一次,如果违反这个规则将抛出一个异常。

每次对元素进行 remove 和 add 都会对 lastRet 进行 -1 的更新 : 个人猜测是因为对 List 进行了修改的缘故

扩展方法源码

/**
 * Represents an operation that accepts a single input argument and returns no
 * result. Unlike most other functional interfaces, {@code Consumer} is expected
 * to operate via side-effects.
 *
 * 表示“接受一个参数输入且没有任何返回值的操作“。不同于其它的函数式接口,Consumer期望通过方法的实现来执行具体的操作。
 *
 * <p>This is a <a href="package-summary.html">functional interface</a>
 * whose functional method is {@link #accept(Object)}.
 *
 * @param <T> the type of the input to the operation
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Consumer<T> {

/**
 * Performs this operation on the given argument.
 * 可实现方法,接受一个参数且没有返回值
 * 
 * @param t the input argument
 */
void accept(T t);

/**
 * Returns a composed {@code Consumer} that performs, in sequence, this
 * operation followed by the {@code after} operation. If performing either
 * operation throws an exception, it is relayed to the caller of the
 * composed operation.  If performing this operation throws an exception,
 * the {@code after} operation will not be performed.
 * 默认方法,提供链式调用方式执行。执行流程:先执行本身的accept在执行传入参数after.accept方法。
 * 该方法会抛出NullPointerException异常。
 * 如果在执行调用链时出现异常,会将异常传递给调用链功能的调用者,且发生异常后的after将不会在调用。
 *
 * @param after the operation to perform after this operation
 * @return a composed {@code Consumer} that performs in sequence this
 * operation followed by the {@code after} operation
 * @throws NullPointerException if {@code after} is null
 */
default Consumer<T> andThen(Consumer<? super T> after) {
    Objects.requireNonNull(after);
    return (T t) -> { accept(t); after.accept(t); };
}

sub

/**
 * Returns a view of the portion of this list between the specified
 * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.  (If
 * {@code fromIndex} and {@code toIndex} are equal, the returned list is
 * empty.)  The returned list is backed by this list, so non-structural
 * changes in the returned list are reflected in this list, and vice-versa.
 * The returned list supports all of the optional list operations.
 * 返回此列表在指定的 {@code fromIndex}(含)和{@code toIndex}(互斥)之间的视图。
 * (如果{@code fromIndex}和{@code toIndex}相等,则返回列表为空。)此列表支持返
 * 回的列表,因此返回列表中的非结构性更改会反映在该列表中,反之亦然。 返回的列表支
 * 持所有可选列表操作。
 * <p>This method eliminates the need for explicit range operations (of
 * the sort that commonly exist for arrays).  Any operation that expects
 * a list can be used as a range operation by passing a subList view
 * instead of a whole list.  For example, the following idiom
 * removes a range of elements from a list:
 * <pre>
 *      list.subList(from, to).clear();
 * </pre>
 * Similar idioms may be constructed for {@link #indexOf(Object)} and
 * {@link #lastIndexOf(Object)}, and all of the algorithms in the
 * {@link Collections} class can be applied to a subList.
 * 这种方法消除了对显式范围运算的需要(这种运算通常在数组中存在)。通过传递 subList
 * 视图而不是整个列表,可以将期望列表的任何操作用作范围操作。例如,以下语句从列表中
 * 删除了一系列元素:<pre> list.subList(from, to).clear(); </pre>
 * 可以为{@link #indexOf(Object)}和{@link #lastIndexOf(Object)}构建类似的
 * 习惯用法,并且{@link Collections}类中的所有算法都可以应用于子列表。
 * <p>The semantics of the list returned by this method become undefined if
 * the backing list (i.e., this list) is <i>structurally modified</i> in
 * any way other than via the returned list.  (Structural modifications are
 * those that change the size of this list, or otherwise perturb it in such
 * a fashion that iterations in progress may yield incorrect results.)
 * 如果后备列表(即此列表)以结构方式(而不是通过返回的列表)进行了修改,则此方法返回的
 * 列表的语义将变得不确定。(结构修改是指更改此列表的大小的结构修改,或者以其他方式干
 * 扰此列表的方式,即正在进行的迭代可能会产生错误的结果。)
 * 
 * @throws IndexOutOfBoundsException {@inheritDoc}
 * @throws IllegalArgumentException {@inheritDoc}
 */
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 {
    // 父 List
    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);
        // 检查 List 是否在操作期间被修改 
        checkForComodification();
        // 对 subList 试图进行 set 赋值,根本上是对源 List 元素进行赋值操作
        // 获取源 List 旧值
        E oldValue = ArrayList.this.elementData(offset + index);
        // 对 源 Lsit 赋新值
        ArrayList.this.elementData[offset + index] = e;
        return oldValue;
    }

    // 获取 subList 试图 index 索引下的元素
    public E get(int index) {
        rangeCheck(index);
        checkForComodification();
        // 本质是根据偏移量 offset 和索引 index 获取 源 List 上的元素
        return ArrayList.this.elementData(offset + index);
    }

    // 获取 subList 视图的大小
    public int size() {
        checkForComodification();
        return this.size;
    }

    public void add(int index, E e) {
        // 边界检查
        rangeCheckForAdd(index);
        // 检查 List 是否在操作期间被修改 
        checkForComodification();
        // 对源 List 进行数据插入,subList 的 index 位置,父 List parentOffset + index 位置
        parent.add(parentOffset + index, e);
        // 更新修改次数
        this.modCount = parent.modCount;
        // 更新 subLsit size
        this.size++;
    }

    public E remove(int index) {
        rangeCheck(index);
        checkForComodification();
        // 对源 List 进行数据删除,subList 的 index 位置,父 List parentOffset + index 位置
        E result = parent.remove(parentOffset + index);
        this.modCount = parent.modCount;
        this.size--;
        return result;
    }

    protected void removeRange(int fromIndex, int toIndex) {
        checkForComodification();
        // 实质是调用父 List remove 方法对父 List 进行范围元素移除
        parent.removeRange(parentOffset + fromIndex,
                           parentOffset + toIndex);
        this.modCount = parent.modCount;
        this.size -= toIndex - fromIndex;
    }

    // 在 subList 尾部添加集合 c 中的元素
    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();
        // 添加集合 c 为空集合,返回 false
        if (cSize==0)
            return false;

        checkForComodification();
        // 实质是调用父 List add 方法对父 List 进行数据添加
        parent.addAll(parentOffset + index, c);
        this.modCount = parent.modCount;
        this.size += cSize;
        return true;
    }

    // 重写了 iterator 方法,在 SubList 中不管调用 iterator 方法,
    // 还是 listIterator 方法都返回的是 ListIterator
    public Iterator<E> iterator() {
        return listIterator();
    }

    // 实际操作的是父 Lsit,方法实现与 ArrayList 的 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();
            }
        };
    }

    // 有种递归的意思,视图产生视图,不过最终所有的操作都是对最起初的源 List 进行操作
    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;
    }
    
    // 根据父 List 的 modCount 检验是否被修改
    private void checkForComodification() {
        if (ArrayList.this.modCount != this.modCount)
            throw new ConcurrentModificationException();
    }

    // 分割迭代器(splitable iterator) 
    // jdk1.8 发布后,对于并行处理的能力大大增强,Spliterator 就是为了并行遍历元
    // 素而设计的一个迭代器,jdk1.8 中的集合框架中的数据结构都默认实现了 spliterator
    public Spliterator<E> spliterator() {
        checkForComodification();
        return new ArrayListSpliterator<E>(ArrayList.this, offset,
                                           offset + this.size, this.modCount);
    }
}

说明

结构性修改 : 是一种操作:添加,删除一个或者多个元素,或者明显的重新调整所背后的数组的大小;仅仅修改元素的内容并不叫结构性修改。

Spliterator

/**
 * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
 * and <em>fail-fast</em> {@link Spliterator} over the elements in this
 * list.
 * 
 * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
 * {@link Spliterator#SUBSIZED}, and {@link Spliterator#ORDERED}.
 * Overriding implementations should document the reporting of additional
 * characteristic values.
 *
 * @return a {@code Spliterator} over the elements in this list
 * @since 1.8
 */
@Override
public Spliterator<E> spliterator() {
    return new ArrayListSpliterator<>(this, 0, -1, 0);
}

static final class ArrayListSpliterator<E> implements Spliterator<E> {
    // 用于存放 ArrayList 对象
   private final ArrayList<E> list;
   // current index, modified on advance/split
   // 当前索引,advance/split 操作时会修改
   private int index;
   // -1 until used; then one past last index
   // 使用的最后一个元素索引,直到使用之前值为 -1
   private int fence;
   // 用于存放 list 当时的 modCount
   private int expectedModCount;
 
   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;
        }
    // 获取结束位置(存在意义:首次初始化石需对 fence 和 expectedModCount 进行赋值)
   private int getFence() {
        int hi;
        ArrayList<E> lst;
        // fence < 0时(第一次初始化时,fence 才会小于0):
        if ((hi = fence) < 0) {
            // list 为 null 时,fence = 0
            if ((lst = list) == null)
                hi = fence = 0;
            else {
            // 否则,fence = list 的长度。
                expectedModCount = lst.modCount;
                hi = fence = lst.size;
            }
        }
        return hi;
    }
    // 分割 list,返回一个新分割出的 spliterator 实例
    public ArrayListSpliterator<E> trySplit() {
        // hi 为当前的结束位置
        // lo 为起始位置
        // 计算中间的位置
        int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
        // 当 lo >= mid,表示不能在分割,返回 null
        // 当 lo <mid 时,可分割,切割(lo,mid)出去,同时更新 index = mid
        return (lo >= mid) ? null :
            new ArrayListSpliterator<E>(list, lo, index = mid, expectedModCount);
    }
    // 返回 true 时,只表示可能还有元素未处理
    // 返回 false 时,没有剩余元素处理了
    public boolean tryAdvance(Consumer<? super E> action) {
         if (action == null)
             throw new NullPointerException();
         // hi 为当前的结束位置
         // i 为起始位置
         int hi = getFence(), i = index;
         // 还有剩余元素未处理时
         if (i < hi) {
             // 处理 i 位置,index + 1
             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) {
            // 当 fence < 0 时,表示 fence 和 expectedModCount 未初始化
            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 处理元素
                    action.accept(e);
                }
                // 遍历时发生结构变更时抛出异常
                if (lst.modCount == mc)
                    return;
            }
        }
        throw new ConcurrentModificationException();
    }
 
    public long estimateSize() {
        return (long) (getFence() - index);
    }
 
    public int characteristics() {
        // 打上特征值:可以返回 size
        return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
    }
}

forEach

@Override
public void forEach(Consumer<? super E> action) {
    // 参数非 null 验证
    Objects.requireNonNull(action);
    // final 修饰一个基本数据类型时只能赋值一次,这样可以保证"安全性"
    final int expectedModCount = modCount;
    @SuppressWarnings("unchecked")
    // final 修饰一个引用类型时,则在对其初始化之后便不能再让其指向其他对象了,
    // 但该引用所指向的对象的内容是可以发生变化的
    final E[] elementData = (E[]) this.elementData;
    final int size = this.size;
    // 对 Lsit 进行全部的遍历,与 foreachRemaining 逻辑相似
    for (int i=0; modCount == expectedModCount && i < size; i++) {
        // 调用 action.accept 处理元素,但是并不修改原有元素
        action.accept(elementData[i]);
    }
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
}

说明
final 修饰变量:
修饰变量是 final 用得最多的地方,也是本文接下来要重点阐述的内容。

  • final 成员变量表示常量,只能被赋值一次,赋值后值不再改变。
  • 当final修饰一个基本数据类型时,表示该基本数据类型的值一旦在初始化后便不能发生变化;如果final修饰一个引用类型时,则在对其初始化之后便不能再让其指向其他对象了,但该引用所指向的对象的内容是可以发生变化的。本质上是一回事,因为引用的值是一个地址,final要求值,即地址的值不发生变化。
  • final修饰一个成员变量(属性),必须要显示初始化。这里有两种初始化方式,一种是在变量声明的时候初始化;第二种方法是在声明变量的时候不赋初值,但是要在这个变量所在的类的所有的构造函数中对这个变量赋初值。
  • 当函数的参数类型声明为final时,说明该参数是只读型的。即你可以读取使用该参数,但是无法改变该参数的值

replace

// java.util.function.UnaryOperator 是一个功能接口,它扩展了 java.util.function.Function
// 接口。 UnaryOperator 接口表示一个操作,它接受一个参数并返回与其输入参数相同类型的结果。
@Override
@SuppressWarnings("unchecked")
public void replaceAll(UnaryOperator<E> operator) {
    Objects.requireNonNull(operator);
    final int expectedModCount = modCount;
    final int size = this.size;
    // 遍历 List 元素,对每个元素进行相应的 operator.apply 操作,最终改变原有的元素
    for (int i=0; modCount == expectedModCount && i < size; i++) {
        elementData[i] = operator.apply((E) elementData[i]);
    }
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
    modCount++;
}

sort

@Override
@SuppressWarnings("unchecked")
public void sort(Comparator<? super E> c) {
    final int expectedModCount = modCount;
    // 利用 Comparator 比较器对 Lsit 进行排序
    // 注意 size,并没有超出数组边界
    // 0 : fromIndex, size : toIndex,因为 Arrays.sort 排序不包括 toIndex,所以
    // 对整个数组进行排序要传入 size
    Arrays.sort((E[]) elementData, 0, size, c);
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
    modCount++;
}

扩展方法源码

// java.util.Arrays

// Arrays.sort((E[]) elementData, 0, size, c)
/**
 * Sorts the specified range of the specified array of objects according
 * to the order induced by the specified comparator.  The range to be
 * sorted extends from index {@code fromIndex}, inclusive, to index
 * {@code toIndex}, exclusive.  (If {@code fromIndex==toIndex}, the
 * range to be sorted is empty.)  All elements in the range must be
 * <i>mutually comparable</i> by the specified comparator (that is,
 * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
 * for any elements {@code e1} and {@code e2} in the range).
 * 根据指定比较器引发的顺序对指定对象数组的指定范围进行排序。要排序的范围从索引
 * {@code fromIndex}到索引{@code toIndex}不包括在内。(如果{@code fromIndex == toIndex},
 * 则要排序的范围为空。)该范围中的所有元素必须可以由指定的比较器相互比较(也就是说,
 * {@ code c.compare(e1,e2)}必须不要为范围内的任何元素{@code e1}和{@code e2}
 * 抛出{@code ClassCastException})。
 * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
 * not be reordered as a result of the sort.
 * 保证这种排序是稳定的:相等元素不会由于排序而重新排序。
 * <p>Implementation note: This implementation is a stable, adaptive,
 * iterative mergesort that requires far fewer than n lg(n) comparisons
 * when the input array is partially sorted, while offering the
 * performance of a traditional mergesort when the input array is
 * randomly ordered.  If the input array is nearly sorted, the
 * implementation requires approximately n comparisons.  Temporary
 * storage requirements vary from a small constant for nearly sorted
 * input arrays to n/2 object references for randomly ordered input
 * arrays.
 * 实施注意事项:此实现是一种稳定的,自适应的,迭代的归并排序,当对输入数组
 * 进行部分排序时,所需的比较少于n lg(n),而当对输入数组进行随机排序时,
 * 它提供了传统归并排序的性能。如果输入数组几乎已排序,则该实现需要大约n个比较。临时
 * 存储要求从几乎排序的输入数组的小常数到随机排序的输入数组的 n / 2个 对象引用,不等。
 * <p>The implementation takes equal advantage of ascending and
 * descending order in its input array, and can take advantage of
 * ascending and descending order in different parts of the the same
 * input array.  It is well-suited to merging two or more sorted arrays:
 * simply concatenate the arrays and sort the resulting array.
 * 该实现在其输入数组中充分利用了升序和降序,并且可以在同一输入数组的不同部分中利用了
 * 升序和降序。它非常适合合并两个或多个排序后的数组:简单地将数组连接起来并对结果数组
 * 进行排序。
 * <p>The implementation was adapted from Tim Peters's list sort for Python
 * (<a href="http://svn.python.org/projects/python/trunk/Objects/listsort.txt">
 * TimSort</a>).  It uses techniques from Peter McIlroy's "Optimistic
 * Sorting and Information Theoretic Complexity", in Proceedings of the
 * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474,
 * January 1993.
 *
 * @param <T> the class of the objects to be sorted : 要排序的对象的类别
 * @param a the array to be sorted : 要排序的数组
 * @param fromIndex the index of the first element (inclusive) to be
 *        sorted : 要排序的第一个元素(包括)的索引
 * @param toIndex the index of the last element (exclusive) to be sorted
 * : 要排序的最后一个元素的索引(不包括)
 * @param c the comparator to determine the order of the array.  A
 *        {@code null} value indicates that the elements'
 *        {@linkplain Comparable natural ordering} should be used.
 * @throws ClassCastException if the array contains elements that are not
 *         <i>mutually comparable</i> using the specified comparator.
 * @throws IllegalArgumentException if {@code fromIndex > toIndex} or
 *         (optional) if the comparator is found to violate the
 *         {@link Comparator} contract
 * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
 *         {@code toIndex > a.length}
 */
public static <T> void sort(T[] a, int fromIndex, int toIndex,
                            Comparator<? super T> c) {
    // 如果没有指定比较器 c 则选择调用 Arrays.sort(Object[] a, int fromIndex, int toIndex)
    // 两者的区别是 sort(Object[] a, int fromIndex, int toIndex) 要求 a 实现了 Comparable
    // 接口
    if (c == null) {
        sort(a, fromIndex, toIndex);
    } else {
        // 边界检查,检查 fromIndex 和 toIndex 是否在范围内
        rangeCheck(a.length, fromIndex, toIndex);
        // 判断是否使用经典的归并排序。在 jdk1.7 以后默认的排序更改为了 TimSort
        if (LegacyMergeSort.userRequested)
            legacyMergeSort(a, fromIndex, toIndex, c);
        else
            TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0);
    }
}

说明

详细见《Arrays 源码阅读笔记》

扩展方法源码

// java.util.TimSort
// TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0);
/**
 * Sorts the given range, using the given workspace array slice
 * for temp storage when possible. This method is designed to be
 * invoked from public methods (in class Arrays) after performing
 * any necessary array bounds checks and expanding parameters into
 * the required forms.
 * 在可能的情况下,使用给定的工作空间数组切片对临时存储区进行排序。此方法
 * 设计为在执行任何必要的数组边界检查并将参数扩展为所需形式之后,从公共方
 * 法(在 Arrays 类中)调用。
 *
 * @param a the array to be sorted
 * @param lo the index of the first element, inclusive, to be sorted
 * 要排序数组的第一个元素的索引,包含
 * @param hi the index of the last element, exclusive, to be sorted
 * 被排序数组的最后一个元素的索引,不包含
 * @param c the comparator to use
 * @param work a workspace array (slice)
 * 工作区数组(切片)
 * @param workBase origin of usable space in work array
 * 工作阵列中可用空间的源数组
 * @param workLen usable size of work array
 * 工作数组的可用大小
 * @since 1.8
 */
static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c,
                     T[] work, int workBase, int workLen) {
    // assert 断言:如果 [ boolean 表达式 ]为 true,则程序继续执行。如果为 false,则程序抛出 AssertionError,并终止执行。
    // 对数据进行合法性校验
    assert c != null && a != null && lo >= 0 && lo <= hi && hi <= a.length;

    // 待排序元素的剩余数量
    int nRemaining  = hi - lo;
    if (nRemaining < 2)
        // Arrays of size 0 and 1 are always sorted
        // 大小为 0 和 1 的数组始终有序
        return;  

    // If array is small, do a "mini-TimSort" with no merges
    // 如果数组很小,执行不使用归并排序的方法 "mini-TimSort"
    if (nRemaining < MIN_MERGE) {
        // 计算数组前部分有序的最大长度,并无论前半部分是升序还是降序,都转为升序
        // initRunLen 最小为 1
        int initRunLen = countRunAndMakeAscending(a, lo, hi, c);
        // 对小数组使用“二分排序”
        binarySort(a, lo, hi, lo + initRunLen, c);
        return;
    }
    
    /**
     * March over the array once, left to right, finding natural runs,
     * extending short natural runs to minRun elements, and merging runs
     * to maintain stack invariant.
     * 从左到右,遍历一边数组。找出自然排好序的序列(natural run),把短的自然升序
     * 序列通过二叉查找排序扩展到 minRun 长度的升序序列。最后合并栈中的所有升序序列,
     * 保证规则不变。
     */
    // 创建一个 TimSort 实例来维护正在进行的排序状态
    TimSort<T> ts = new TimSort<>(a, c, work, workBase, workLen);
     // 主要将数组分为一个个的 minRun,最后在进行合并,如果长度为 2 的 n 次幂,minRun 为 32,
     // 否则为 16 - 32 之间的数.
    int minRun = minRunLength(nRemaining);
    do {
        // Identify next run : 确定下一次运行
        // 找到下一段 a 中已经有序的元素个数
        int runLen = countRunAndMakeAscending(a, lo, hi, c);

        // If run is short, extend to min(minRun, nRemaining)
        // 果有序个数小于上面的 minRun,则扩展到 min(minRun,nRemaining)
        if (runLen < minRun) {
            int force = nRemaining <= minRun ? nRemaining : minRun;
            // 通过二分排序扩展有序数组
            binarySort(a, lo, lo + force, lo + runLen, c);
            // 跟新下一段 a 中已经有序的元素个数
            runLen = force;
        }

        // Push run onto pending-run stack, and maybe merge
        // 把已经排好序的数列压入栈中,检查是不是需要合并
        ts.pushRun(lo, runLen);
        // 检查栈中待归并的升序序列
        ts.mergeCollapse();

        // Advance to find next run
        // 把指针后移 runLen距离,准备开始下一轮片段的排序
        lo += runLen;
        // 剩下待排序的数量相应的减少 runLen
        nRemaining -= runLen;
    } while (nRemaining != 0);

    // Merge all remaining runs to complete sort
    // 合并所有剩余运行以完成排序
    assert lo == hi;
    ts.mergeForceCollapse();
    assert ts.stackSize == 1;
}

说明

详细见 《TimSort 源码阅读笔记》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值