JAVA集合之ArrayList源码解析

JAVA集合之ArrayList源码解析

本人想写博客很久了,这是我的第一篇博客,之后我也会陆陆续续的把JAVA的集合篇补全,废话不多说,让我们开始曹飞ArrayList(1.8JDK)

继承关系JAVA集合的继承关系

在上图我们可以看到ArrayList的继承关系和优缺点

  1. 排序有序,可重复
  2. 底层使用数组
  3. 读取速度快,增删速度慢
  4. 线程不安全
  5. 按1.5倍扩容
    接下来,我将从源码层分析为何ArrayList具有此种特性。

源码解析

简介和继承关系

我们看源码,一定要先看它的注释

/**
 * Resizable-array implementation of the <tt>List</tt> interface.  Implements
 * all optional list operations, and permits all elements, including
 * <tt>null</tt>.  In addition to implementing the <tt>List</tt> interface,
 * this class provides methods to manipulate the size of the array that is
 * used internally to store the list.  (This class is roughly equivalent to
 * <tt>Vector</tt>, except that it is unsynchronized.)
 *
 * <p>The <tt>size</tt>, <tt>isEmpty</tt>, <tt>get</tt>, <tt>set</tt>,
 * <tt>iterator</tt>, and <tt>listIterator</tt> operations run in constant
 * time.  The <tt>add</tt> operation runs in <i>amortized constant time</i>,
 * that is, adding n elements requires O(n) time.  All of the other operations
 * run in linear time (roughly speaking).  The constant factor is low compared
 * to that for the <tt>LinkedList</tt> implementation.
 *
 * <p>Each <tt>ArrayList</tt> instance has a <i>capacity</i>.  The capacity is
 * the size of the array used to store the elements in the list.  It is always
 * at least as large as the list size.  As elements are added to an ArrayList,
 * its capacity grows automatically.  The details of the growth policy are not
 * specified beyond the fact that adding an element has constant amortized
 * time cost.
 *
 * <p>An application can increase the capacity of an <tt>ArrayList</tt> instance
 * before adding a large number of elements using the <tt>ensureCapacity</tt>
 * operation.  This may reduce the amount of incremental reallocation.
 *
 * <p><strong>Note that this implementation is not synchronized.</strong>
 * If multiple threads access an <tt>ArrayList</tt> instance concurrently,
 * and at least one of the threads modifies the list structurally, it
 * <i>must</i> be synchronized externally.  (A structural modification is
 * any operation that adds or deletes one or more elements, or explicitly
 * resizes the backing array; merely setting the value of an element is not
 * a structural modification.)  This is typically accomplished by
 * synchronizing on some object that naturally encapsulates the list.
 *
 * If no such object exists, the list should be "wrapped" using the
 * {@link Collections#synchronizedList Collections.synchronizedList}
 * method.  This is best done at creation time, to prevent accidental
 * unsynchronized access to the list:<pre>
 *   List list = Collections.synchronizedList(new ArrayList(...));</pre>
 *
 * <p><a name="fail-fast">
 * The iterators returned by this class's {@link #iterator() iterator} and
 * {@link #listIterator(int) listIterator} methods are <em>fail-fast</em>:</a>
 * if the list is structurally modified at any time after the iterator is
 * created, in any way except through the iterator's own
 * {@link ListIterator#remove() remove} or
 * {@link ListIterator#add(Object) add} methods, the iterator will throw a
 * {@link ConcurrentModificationException}.  Thus, in the face of
 * concurrent modification, the iterator fails quickly and cleanly, rather
 * than risking arbitrary, non-deterministic behavior at an undetermined
 * time in the future.
 *
 * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
 * as it is, generally speaking, impossible to make any hard guarantees in the
 * presence of unsynchronized concurrent modification.  Fail-fast iterators
 * throw {@code ConcurrentModificationException} on a best-effort basis.
 * Therefore, it would be wrong to write a program that depended on this
 * exception for its correctness:  <i>the fail-fast behavior of iterators
 * should be used only to detect bugs.</i>
 *
 */

全是英文不用怕,打开翻译软件翻译一下

/ * *
* 列表接口的可调整数组实现。实现了
*所有可选列表操作,并允许所有元素,包括
* 空。除了实现列表接口外,
这个类提供了操作数组大小的方法
*用于内部存储列表。这个类大致相当于
* Vector,但不同步
* 
*size,isEmpty,get,set,
* iterator,和listIterator操作在常量中运行
*时间。add操作运行于摊销常数时间,
即添加n个元素需要O(n)时间。所有其他的操作
以线性时间运行(粗略地说)。常数因子比较低
*为LinkedList实现。
*
* 每个ArrayList实例有一个容量。的能力是
*用于存储列表中元素的数组的大小。它总是
*至少和列表大小一样大。当元素被添加到ArrayList时,
它的容量会自动增长。而增长政策的细节则没有
*除了增加一个元素具有常数平摊的事实之外
*时间成本。
*
一个应用程序可以增加ArrayList实例的容量
*在使用ensureCapacity添加大量元素之前
*操作。这可能会减少增量重新分配的数量。
*
* 注意此实现没有同步
*如果多个线程并发访问ArrayList实例,
*和至少一个线程修改列表的结构,它
* 必须外部同步。结构的改变是
*任何添加或删除一个或多个元素的操作,或显式地
*调整支持数组的大小;仅仅设置元素的值是不行的
结构修改。)这通常由
*同步一些对象,自然封装了列表。
*
*如果没有这样的对象存在,则列表应该使用
* {@link Collections#synchronizedList Collections.synchronizedList}
*方法。这最好在创建时完成,以防止意外
*对列表的非同步访问
*
* < p > < name = "快速失败”>
*这个类的{@link #iterator() iterator}和返回的迭代器
* {@link #listIterator(int) listIterator}方法为<em>fail-fast</em>:</a>
*如果列表在迭代器被修改后的任何时候被修改
*以任何方式创建,除了通过迭代器自己
* {@link ListIterator#remove() remove}* {@link ListIterator#add(Object) add}方法,迭代器将抛出一个
* {@link ConcurrentModificationException}。因此,在面对
*并发修改时,迭代器会快速而干净地失败
*而不是冒险在一个不确定的情况下做出任意的、不确定的行为
*未来的时间。
*
*注意,不能保证迭代器的快速失败行为
一般来说,要在合同中作出任何硬性保证是不可能的
*存在不同步的并发修改。快速失败迭代器
*尽最大努力抛出{@code ConcurrentModificationException}
因此,依赖于此来编写程序是错误的
*对其正确性的异常:<i>迭代器的快速失败行为
*只用于检测bug。</i>
*/

通过翻译,我们大致了解了ArrayList的各种特点,下面来看源码
在这里插入图片描述
ArrayList继承AbstractList抽象类,实现了List接口,RandomAccess接口,Cloneable接口,实现了序列化
在这里插入图片描述
为什么AbstractList实现了List接口后,我们的ArrayList还要去实现LIst接口呢?因为AbstractList是一个抽象类,它并没有全部实现List的方法,这一点我们在ArrayList的方法里也可以看出来
在这里插入图片描述
我们可以看到ArrayList不仅重写了AbstractList的方法,也实现了List接口的方法。

ArrayList实现Cloneable接口为了可以通过克隆的方法创建对象,ArrayList实现RandomAccess接口表示ArrayList实现了快速随机访问

/**
 * Marker interface used by <tt>List</tt> implementations to indicate that
 * they support fast (generally constant time) random access. 
 * */
public interface RandomAccess {
}
RandomAccess接口只是为了标识,实现这个类的实现类都支持fast random access. (快速随机访问)

看完继承关系,我们接下来看内部的变量

内部变量

/**
     * 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的容量是这个数组缓冲区的长度。任何
	空的ArrayList 当 elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA时
	将在添加第一个元素时扩展为DEFAULT_CAPACITY>>10transient Object[] elementData; // non-private to simplify nested class access
    非私有简化嵌套类访问,不会被序列化
    
    private int size;大小
	

构造方法

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);
        }
    }
public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_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;
        }
    }    

ArrayList三个构造函数,可传入数值和集合。

添加方法

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

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }
public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
        return numNew != 0;
    }
public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);

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

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

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

ArrayList的添加方法默认是在末尾进行添加,当指定位置添加时,会调用rangeCheckForAdd进行越界检查,当指定的下标大于ArrayList的大小或小于0时,抛出下标越界异常
在这里插入图片描述
检查下标合法之后,ArrayList调用ensureCapacityInternal方法来确保内部容量,简单点说就是扩容。
在这里插入图片描述
内部通过calculateCapacity计算实际扩容大小,ifArrayList为空时,取默认扩容因子(10)和传入参数(size+添加元素大小)进行比较,取最大值进行扩容,else取传入参数。
在这里插入图片描述
继续进行判断,进入实际扩容代码前,再次判断是否进行扩容,阻止添加空元素进行扩容的情况
在这里插入图片描述
终于进入实际扩容代码了,默认进行1.5倍的扩容,然后跟传入参数进行比较,取最大值,当扩容大小>Integer.MAX_VALUE - 8,取Integer.MAX_VALUE:2^31-1,所以,ArrayList的最大值就是 Integer.MAX_VALUE
在这里插入图片描述
通过新建一个数组的方法来进行扩容。
在这里插入图片描述

删除方法

重点来了各位,ArrayList最困扰我的一部分就在这里,大家听我细细分说。

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

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

        return anyToRemove;
    }
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;
    }

remove(int index)方法里,通过下标进行删除,首先通过rangeCheck检查下标是否越界,之后取出老数据返回,然后算出需要移动的步数,通过System.arraycopy方法进行复制,此方法不会使数组的大小缩减,举个简单的例子

 Object arr[]={1,2,3,4,5};
 
 System.arraycopy(arr,4,arr,3,1);
 第一个参数:原始的数组 第二个参数:原始数组开始复制的下标 
 第三个参数:接收的数组 第四个参数:接收的数组从哪个下标开始复制 
 第五个参数:复制的长度
 复制之后的结果:{1,2,3,5,5},数组的长度还是5
 

我们本来的目的是进行删除,通过复制并没有使数组长度缩减,还多了一位我们不需要的数据,ArrayList接下来做了一个很骚的操作,我愿称之为骚王
elementData[--size] = null; // clear to let GC do its work手动加粗!!!!
这句话到底有什么用,它首先把ArrayList的size进行自减,这没啥好说的,size表示ArrayList的大小,但这只是个标识位,跟实际数据elementData[]数组的长度并没有直接的关系,加下来它将elementData[size-1]的数据置为了null,最后一位置为了null,但这同样没啥卵用,因为ArrayList是可以存null的,那为什么就算移除了呢,我百思不得其解,我尝试着写了一个案例

List<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        list.add("3");
        list.add("4");
        list.add("5");
        list.remove(3);
        System.out.println(list);
 输出结果:[1, 2, 3, 5]   

首先查看ArrayList的toString方法,并没有找到,在它的父类AbstractCollection中重写了toString方法

public String toString() {
        Iterator<E> it = iterator();
        if (! it.hasNext())
            return "[]";

        StringBuilder sb = new StringBuilder();
        sb.append('[');
        for (;;) {
            E e = it.next();
            sb.append(e == this ? "(this Collection)" : e);
            if (! it.hasNext())
                return sb.append(']').toString();
            sb.append(',').append(' ');
        }
    }

通过迭代器进行遍历,拼接字符串,看起来也没有什么问题,我们继续进入it.hasNext()方法

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

真相大白!它根本不会去查找置为null的那个数组元素,因为size已经-1了
回过头来再来看,ArrayList初始数组就是长度为10的数组,但size却是0就很好理解了,ArrayList遍历是根据size来遍历的,从来不是内部数组的真实大小!

其他方法

删除集合中所有元素
public boolean removeAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, false);
    }
保留集合中所有元素
public boolean retainAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, true);
    }
具体删除方法
private boolean batchRemove(Collection<?> c, boolean complement) {
        final Object[] elementData = this.elementData;
        int r = 0, w = 0;
        boolean modified = false;
        try {
            for (; r < size; r++)
                if (c.contains(elementData[r]) == complement)
                    elementData[w++] = elementData[r];
        } finally {
            // Preserve behavioral compatibility with AbstractCollection,
            // even if c.contains() throws.
            if (r != size) {
                System.arraycopy(elementData, r,
                                 elementData, w,
                                 size - r);
                w += size - r;
            }
            if (w != size) {
                // clear to let GC do its work
                for (int i = w; i < size; i++)
                    elementData[i] = null;
                modCount += size - w;
                size = w;
                modified = true;
            }
        }
        return modified;
    }

batchRemove这个方法十分的精妙,阅读起来也不怎么好理解。

    private boolean batchRemove(Collection<?> c, boolean complement) {
    final Object[] elementData = this.elementData;
    //首先初始化两个坐标都为0
    int r = 0, w = 0;
    boolean modified = false;
    try {
        for (; r < size; r++)//r自增
            if (c.contains(elementData[r]) == complement)//删除方法complement为false
                elementData[w++] = elementData[r];
                在进行删除时,c.contains(elementData[r]) 为fasle,两者不同,
                w会保持和r一起自增,
                而当匹配到相同元素时,if失效,w会比r小,
                下次再匹配不到时,w,r不同,将进行替换,
                而w正是上一次的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;
            w小于size的原因就是if失效,就是匹配到了数据,
            所以说w比size少多少,就能体现出删除了多少个数据,
            w以后的数据就是废数据,直接置为null,再将size修改,remove的操作就完成了
        }
    }
    return modified;
}

更直白的解释请参考 ArrayList 里的 removeAll() 及 batchRemove() 方法【可能让你感受到jdk之美的文章】.

内部类

Array List有三个内部类,分别为Itr,ListItr,SubList,ArrayListSpliterator 前两个为迭代器,SubList为Array List的部分截取,ArrayListSpliterator 是一个可以分割的迭代器,可以将Spilterator实例分割成多个小的Spilterator实例。

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

Itr为一个标准的Iterator实现类,实现了Next()向前遍历。

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

ListItr则是ListIterator的实现类,包括向前,向后遍历,添加,修改方法。

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);
        }
    }

SubList是返回ArrayList的一部分,我们看到SubList的构造函数中,数据是直接指向传入的List的,也就是说,改变SubList也会改变原List的内部数据。

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;
        }
   }

它的get,set,add,remove全部调用的传入List的方法。将它当作视图或者放大镜更好理解,它只是用来减少传入List暴露在外面的数据使用,可以查看,但不要将它当成独立的一个新List来使用!!!

spliterator的内容我就不说了推荐一下这篇文章,讲的很详细

ArrayList源码分析(下)——Java8中新增的Spliterator的分析

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值