ArrayList 源码坑读学习记录

Field
DEFAULT_CAPACITY

这个属性是ArrayList的容量,默认初始就赋值位10,如果构造函数没有出入集合容量的话,就会用这个默认的初始化容量

private static final int DEFAULT_CAPACITY = 10;
EMPTY_ELEMENTDATA

初始化一个Object类型的空数组对象,用于后续方法调用

private static final Object[] EMPTY_ELEMENTDATA = {};
DEFAULTCAPACITY_EMPTY_ELEMENTDATA

初始化一个默认的Object类型的空数组对象,这个与上面的空数组对象没什么区别,只是代码中用来区别不同的新建数组的方式

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
elementData

这个elementData属性是ArrayList用来存储数据的,初始化的时候ArrayList的容量capacity的大小就等于elementData的length长度,这就可以看出来ArrayList的内部数据结构就是Object类型的数组,且这个属性用transient修饰了,被这个修饰符修饰的属性在序列化的时候不会序列化进去

transient Object[] elementData; // non-private to simplify nested class access
为啥要用transient修饰elementData使其不被序列化

elementData是一个缓存数组,它通常会预留一些容量,等容量不足时再扩充容量。假如现在实际有了5个元素,而elementData的大小可能是10,那么在序列化时只需要储存5个元素,数组中的最后五个元素是没有实际意义的,不需要储存。所以ArrayList的设计者将elementData设计为transient,然后在writeObject方法中手动将其序列化,并且只序列化了实际存储的那些元素,而不是整个数组

size

size这个属性是标识ArrayList集合中有多少个元素,eg:1,2,3 这样size=3

private int size;
MAX_ARRAY_SIZE

这个是一个静态常量,提供一个Integer的最大值-8的值,这个值为啥是231-8,主要是怕虚拟机VM内存溢出出现OutOfMemoryError错误,其次就是数组对象有一些自己的元信息需要8个字节,所以一般都是231-8。

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
modCount

这个是父类AbstractList集合的一个属性,作用是用来记录集合的数据机构的修改次数,增删改都会用这个属性去记录次数。

protected transient int modCount = 0;
Method
ArrayList(int initialCapacity)

这个是一个接收指定容量参数initialCapacity,根据参数值来初始化elementData数组,如果传入的容量大于0就new一个Object数组长度为initialCapacity的数组,如果传入的容量等于0就直接把属性初始化好的一个空数组对象赋值给elementData,否则就抛出IllegalArgumentException非法参数异常

public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    }
}
ArrayList()

这个无参的构造函数直接把属性中初始化好的默认空数组赋值给elementData

public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
ArrayList(Collection<? extends E> c)

这个构造函数是接收一个集合对象参数C,把C集合转化成数组然后赋值给elementData,再利用elementData数组的长度判断是否等于集合的大小Size这个时候size的大小还是0的,所以如果不相等elementData就直接等于属性中的空数组了,如果不相等就利用Arrays.copyOf的数组拷贝方法把数组按size的大小拷贝一个新对象赋值给elementData数组。

public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    if ((size = elementData.length) != 0) {
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        // replace with empty array.
        this.elementData = EMPTY_ELEMENTDATA;
    }
}
copyOf(U[] original, int newLength, Class<? extends T[]> newType)

这个Arrays类中的一个数组的拷贝方法,该方法接收单个参数,original:拷贝之前的数组,newLength:拷贝之际后新数组的长度length, newType:新数组数据的类型。首先根据newType的类型新建一个拷贝之际后的数组,如果newType类型为Object类型就直接new一个Object的数组长度为newLength,如果不是Object类型就利用Arrays.newInstance方法新建一个指定类型的数组,最后把新建出来的新数组和其他三个参数传入System.arraycopy()方法执行数组的具体拷贝操作,

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;
}
arraycopy(Object src, int srcPos,Object dest, int destPos,int length)

这个方法是native本地方法,这种一般都不是java自己执行,都是委托给别人执行,只需要按参数传入就可以了。

public static native void arraycopy(Object src,  int  srcPos,
                                    Object dest, int destPos,
                                    int length);
trimToSize()

这个方法主要是修剪一下ArrayList的容量,会拿size与elementData的长度去比较,如果size小于数组的长度且elementData数组长度为0也就是说size和数组的长度都为0就设置elementData数组为属性中定义好的空数组对象,否则就调用Arrays.copyOf()方法拷贝elementData,拷贝数据大小为size,拷贝类型为elementData的数据类型,最后会用modCount++记录修改次数。

public void trimToSize() {
    modCount++;
    if (size < elementData.length) {
        elementData = (size == 0)
          ? EMPTY_ELEMENTDATA
          : Arrays.copyOf(elementData, size);
    }
}
ensureCapacity(int minCapacity)

修改ArrayList的容量以确保最少可以存下指定参数minCapacity容量的数据,首先判断elementData数组对象是否为默认的空数组对象属性,如果是就设置minExpand=10,否则设置minExpand=0,最后判断minCapacity是否小于minExpand,小于就调用ensureExplicitCapacity(minExpand)方法修改集合容量,否则不做修改容器的处理。

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);
    }
}
ensureCapacityInternal(int minCapacity)

这个方法修饰为private只能内部调用,方法的作用也是根据传入指定容量参数来判断是否需要修改集合的容量,分别会调用calculateCapacity()方法和ensureExplicitCapacity()计算。

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

这个也是内部调用方法,根据传入的数组对象判读是否位属性中默认的空数组对象,如果是就取传入的容量参数和默认容量10中最大的值,否则就直接使用参数容量大小。

private static int calculateCapacity(Object[] elementData, int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
}
ensureExplicitCapacity(int minCapacity)

这个也是内部方法,主要是通过传入的指定容量参数判断是否大于elementData数组的长度,如果大于就调用grow()方法重新计算容量大小按这个容量重新拷贝一个新的数组给ArrayList的elementData数组属性。

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}
grow(int minCapacity)

这个方法就是根据容量大小重新拷贝一个数组对象赋值给elementData数组对象,首先拿拷贝之前的elementData的长度,然后把这个长度利用右位运算在原来值的基础上加原来的1/2长度(4 -> 4+4/2=6)赋值给newCapaciry,然后判断newCapaciry是否小于传入的容量参数minCapaciry,如果小于就把minCapaciry赋值为newCapacity,接着还要拿newCapaciry去判断是否大于Max_ARRAY_SIZE,如果大于就调用hugeCapacity()方法取一个容量值赋值给newCapacity,最后调用Arrays.copyOf传入newCapaciry和elementData数组拷贝出一个新容量的数组赋值给elementData数组。

private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    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);
}
hugeCapacity(minCapacity)

根据指定的容量参数判断是否大于MAX_ARRAY_SIZE,如果大于就用Integer.MAX_VALUE(231),否则就用231-8。

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

返回集合中有多少个元素,即属性size的大小

public int size() {
    return size;
}
isEmpty()

判断集合是否为空,主要是判断size是否等于0,等于0就为空,否则不为空。

public boolean isEmpty() {
    return size == 0;
}
indexOf(Object o)

根据传入参数对象查询首次出现在集合数组中的下标,这个对象可以是null这个参数需要满足(o==null || o.equals(elementData[i])),如果对象为null就循环判断elementData数组中是否有为null的数据如果有就返回该数据的数组下标,否则查询o.equals(elementData[i])相等的数据,找到就返回相应的数组下标,如果以上两种判断都不满足就返回-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;
}
contains(Object o)

该方法判断ArrayList集合中是否包含指定参数对象,其实就把这个参数传入到Indexof(o)中查询对应的下标,如果>=0说明找到了下标也就是包含这个数据,否则不包含。

public boolean contains(Object o) {
    return indexOf(o) >= 0;
}
lastIndexOf(Object o)

根据传入参数对象查询最后出现在集合数组中的下标,这个对象可以是null这个参数需要满足(o==null || o.equals(elementData[i])),如果对象为null就循环判断elementData数组中是否有为null的数据如果有就返回该数据的数组下标,否则查询o.equals(elementData[i])相等的数据,找到就返回相应的数组下标,如果以上两种判断都不满足就返回-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;
}
clone()

这个是ArrayList集合克隆的方法,利用Object类中的Native 本地方法clone()新建一个对象出来把这个对象强转成ArrayList,再把被克隆的集合的elementData和size传入Arrays.copyof拷贝一个elementData数组赋值给新建出来集合的elementData,最后返回这个新建的对象。

public Object clone() {
    try {
        ArrayList<?> v = (ArrayList<?>) super.clone();
        v.elementData = Arrays.copyOf(elementData, size);
        v.modCount = 0;
        return v;
    } catch (CloneNotSupportedException e) {
        // this shouldn't happen, since we are Cloneable
        throw new InternalError(e);
    }
}
elementData(int index)

根据传入的数组下标获取相应的数组下标的数据,这个修饰不是public公开的。

E elementData(int index) {
    return (E) elementData[index];
}
toArray()

这个其实就是把elementData数组和size传入Array.copyof拷贝一个elementData数组返回。

public Object[] toArray() {
    return Arrays.copyOf(elementData, size);
}
toArray(T[] a)

这个根据传入的数组对象的类型拷贝一个新的数组,也是利用的Arrays.copyof方法。

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;
}
get(int index)

根据传入的数组下标获取对象的数组数据,首先判断下标是否越界,会判断是否大于size或者小于0如果满足其中一条就抛出下标越界异常,否则就根据下标获取对应的数组数据。

public E get(int index) {
    rangeCheck(index);

    return elementData(index);
}
set(int index, E element)

根据传入的数组下标和数据替换数组中该下标的数据,首先判断下标是否越界,会判断是否大于size或者小于0如果满足其中一条就抛出下标越界异常,接着把该下标的数据取出来返回出去,最后再把传入的数据放到这个数组下标中。

public E set(int index, E element) {
    rangeCheck(index);

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

首先会把size+1作为参数取计算容量是否足够,如果足够就不重新计算容量不足够就会重新计算容量拷贝一个新的数组,最后把这个参数数据添加到size下标,也就是把数据保存到数组最后的一个位置,新增完后把size++。

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}
add(int index, E element)

这个方法与上面那个add(e)方法有点不一样这个是根据参数下标再这个下标新增一个数据,首先判断下标是否越界,然后再把size+1去计算容量是否需要扩容,再调用System.arraycopy把参数下标index之后的所有数据都右移,最后把空出来的index这个下标位置填入参数element数据,再把size++。

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++;
}
remove(int index)

移除指定下标的数据,检查参数下标是否越界,把记录修改次数的modCount++,把该下标的数据取出来用于最后返回,计算需要移动的数据,然后调用System.copyof()方法把这个下标的之后的数据左移,移动完成后把数组最后一个数据设置为null,最后返回这个下标移动之前的数据。

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;
}
remove(Object o)

根据传入的对象数据移除集合中的这个数据,首先判断是对象是否为null循环判断数组是否有null的数据如果有就把这个数组的下标传入fastRemove()方法中做移除的操作,其次使用equals方法循环判断与数组中的数据是否相等如果相等就把数组中这个数据的下标传入fastRemove()方法中做移除的操作,如果以上两种判断都不满足就返回false,否则返回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;
}
fastRemove(int index)

根据传入的数组下标计算出需要左移动的数据,然后使用system.copy()方法把传入的下标之后的数据都往左移动,移动完成后把数组最后一个数组设置为null。

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
}
clear()

循环把数组的数据都设置为null,且把size设置为0,记录修改次数modcount

public void clear() {
    modCount++;

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

    size = 0;
}
addAll(Collection<? extends E> c)

在集合后面添加一个集合对象,首先把参数集合对象变成数据对象,然后把这个数组对象的长度+size去计算容量是否需要扩容,最后把参数集合数组对象和elementData传入system.copy()方法拷贝一个新的数组对象出来,长度为size+参数数组的长度。

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;
}
addAll(int index, Collection<? extends E> c)

在指定位置新增一个集合对象数据,首先判断传入的下标是否越界,然后把数组对象参数的长度+size去判断是否需要扩容,接着去判断size是否大于参数下标,如果大于就把index之后的数据移动到index+参数数据的长度之后下标,最后再把参数数组拷贝到移动之后的数组中,把size设置为size+参数数组的长度。

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;
}
removeRange(int fromIndex, int toIndex)

移除指定下标范围的数据,首先判断移除指定范围的数据之后是否需要移动数据,如果需要就左移动数据,然后再把移动之后的一些重复的数据设置为null,把size重新设置为新的大小。

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;
}
rangeCheck(int index)

判断下标是否大于size,或者小于0,如果是的就抛出下标越界的异常

private void rangeCheck(int index) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
rangeCheckForAdd(int index)

判断下标是否大于size,或者小于0,如果是的就抛出下标越界的异常

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

数组下标越界的信息组装

private String outOfBoundsMsg(int index) {
    return "Index: "+index+", Size: "+size;
}
removeAll(Collection<?> c)

移除参数中指定的集合数据,首先调用Object.requireNonNull判断该集合不能null否则抛空指针异常,最后调用batchRemove去做批量移除数据。

public boolean removeAll(Collection<?> c) {
    Objects.requireNonNull(c);
    return batchRemove(c, false);
}
retainAll(Collection<?> c)

保留参数中指定的集合数据,首先调用Object.requireNonNull判断该集合不能null否则抛空指针异常,最后调用batchRemove去做批量移除不是参数集合中其他数据。

public boolean retainAll(Collection<?> c) {
    Objects.requireNonNull(c);
    return batchRemove(c, true);
}
batchRemove(Collection<?> c, boolean complement)

批量移除数据,循环判断参数集合c是否包含element数组中的数据,如果传入的complement就是记录不包含的数据,否则记录的就是包含的数据,最后会把匹配的数据之外的所有数据都设置为null,重新设置一下集合的大小size,且把是否修改标识设置为已修改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;
}
writeObject(java.io.ObjectOutputStream s)

这个是手动序列化数据的方法把数据序列化到ObjectOutputStream中,首先记录修改次数给expModCount属性最后会判断这个属性与modCount属性是否相等,如果不相等就抛出ConcurrentModificationException异常,接着调用s.defaultWriteObject()这个方法主要是序列化没有被transient修饰的其他数据,接着序列化数组的大小s.writeInt(size),最后循环序列化数组的数据。

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();
    }
}
readObject(java.io.ObjectInputStream s)

从ObjectInputStream流中反序列化数据出来,首先调用s.defaultReadObject()反序列化不是transient修饰的数据,接着执行s.readInt()这个方法被注释为可以忽略,再根据反序列化出来的数组大小判读是否需要扩容,如果需要扩容就先扩容,最后再把被transient修饰的elementData数据反序列化出来保存到扩容后的数组对象里。

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();
        }
    }
}
listIterator(int index)

根据传入的下标调用内部类ListItr(index)构造函数新建一个ListItr对象。

public ListIterator<E> listIterator(int index) {
    if (index < 0 || index > size)
        throw new IndexOutOfBoundsException("Index: "+index);
    return new ListItr(index);
}
listIterator()

调用内部类ListItr(index)构造函数新建一个index下标为0的ListItr对象。

public ListIterator<E> listIterator() {
    return new ListItr(0);
}
iterator()

调用内部类构造函数Itr(),新建一个Itr对象。

public Iterator<E> iterator() {
    return new Itr();
}
forEach(Consumer<? super E> action)

这个是一个forEach方法循环调用函数接口Consumer.accept方法处理,函数接口就是利用labom表达式处理的。

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();
        }
    }
sort(Comparator<? super E> c)

集合的排序方法也是利用的函数接口Comparator,调用Arrays.sort处理。

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++;
}
subList(int fromIndex, int toIndex)

根据指定范围截取集合。

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

判断这两个是否越界。

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 + ")");
}
AnonymousInnerClass
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();
    }
}
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();
        }
    }
}
ArrayListSpliterator 类
static final class ArrayListSpliterator<E> implements Spliterator<E> {

    /*
     * If ArrayLists were immutable, or structurally immutable (no
     * adds, removes, etc), we could implement their spliterators
     * with Arrays.spliterator. Instead we detect as much
     * interference during traversal as practical without
     * sacrificing much performance. We rely primarily on
     * modCounts. These are not guaranteed to detect concurrency
     * violations, and are sometimes overly conservative about
     * within-thread interference, but detect enough problems to
     * be worthwhile in practice. To carry this out, we (1) lazily
     * initialize fence and expectedModCount until the latest
     * point that we need to commit to the state we are checking
     * against; thus improving precision.  (This doesn't apply to
     * SubLists, that create spliterators with current non-lazy
     * values).  (2) We perform only a single
     * ConcurrentModificationException check at the end of forEach
     * (the most performance-sensitive method). When using forEach
     * (as opposed to iterators), we can normally only detect
     * interference after actions, not before. Further
     * CME-triggering checks apply to all other possible
     * violations of assumptions for example null or too-small
     * elementData array given its size(), that could only have
     * occurred due to interference.  This allows the inner loop
     * of forEach to run without any further checks, and
     * simplifies lambda-resolution. While this does entail a
     * number of checks, note that in the common case of
     * list.stream().forEach(a), no checks or other computation
     * occur anywhere other than inside forEach itself.  The other
     * less-often-used methods cannot take advantage of most of
     * these streamlinings.
     */

    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;
    }
}
SubList 类
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);
    }
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值