关于ArrayList源码的一些自我理解以及解析(五):sublist方法原来如此

之前了解了ArrayList的一个内部类Itr,在看了Itr的源码之后,知道它是如何工作的,以及知道并了解了cursor和lastRet之间的关系。在后面发现了Itr的子类:

    /**
     * An optimized version of AbstractList.ListItr
     */
    private class ListItr extends Itr implements ListIterator {
        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() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            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();
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            try {
                ArrayList.this.set(lastRet, e);
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
        public void add(E e) {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            try {
                int i = cursor;
                ArrayList.this.add(i, e);
                cursor = i + 1;
                lastRet = -1;
                expectedModCount = modCount;
                limit++;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
    }

同样是ArrayList的内部类,对这个内部类的注释和Itr一样,是AbstractList.ListItr的优化版本。

        ListItr(int index) {
            super();
            cursor = index;
        }
        public boolean hasPrevious() {
            return cursor != 0;
        }
        public int nextIndex() {
            return cursor;
        }
        public int previousIndex() {
            return cursor - 1;
        }

构造方法只有一个。传递一个int类型的参数,然后将这个参数赋值给父类的cursor。之所以没有在Itr中给cursor一个明确的值,是为了让子类去给cursor赋值,让cursor一开始就指着某个位置。

hasPrevious方法,从字面上理解,就是是否有上一个元素。比如,当cursor=0的时候,表示此时cursor指向的是第一个元素的下标,都已经指着第一个元素呢,怎么可能还有上一级的元素呢。

nextIndex方法,返回的参数是cursor的值。方法名字的翻译是下一个下标索引,我们再看另外一个方法。

previousIndex方法,返回的是cursor-1。这个方法名字的翻译是上一个下标索引,想象一下nextIndex的使用场景。我们第一次使用迭代器,假设这时候cursor指向的是下标索引为0的第一个元素。我们第一次使用,然后接下来要进行遍历了,你大喊一句”把下一个下标索引给我拿过来!“,然后nextIndex将cursor给了你,你一看没有毛病,然后开始操作,并使用next()方法,在next方法中cursor+1了,但是你为了确保不失误,于是你又大喊”下一个下标索引给我拿过来“,再看一下没毛病就又操作,于是就如此反复操作。

说了这么多,nextIndex方法说白了,就是让我们确保,操作的下标索引是我们想要的。也就是说,这个方法很有可能是后续代码进行判断的时候使用,或者开发人员进行判断使用的。

        @SuppressWarnings("unchecked")
        public E previous() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            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];
        }

previous方法,首先是很熟悉的if (modCount != expectedModCount)判断,然后将cursor-1的值赋给了i,也就是说指向的是上一个元素内容,然后进行if检查,如果cursor本来就指着第一个元素,自然就没有上一个了。然后又是熟悉了if判断,由于随后cursor被赋值了i,可以看成,实际上cursor进行了自我-1操作。最后叫lastRet将相应的下标取出来。

这个方法实现的是游标上移或者说后退一步,正常情况下cursor后面是跟着lastRet的,调用了previous方法后,cursor后退了一步,和lastRet重合了。

比如,有一个长度为5数组内容是01234的数组,如果我们一直执行next()方法,不断的取出数来,那么取出来数的顺序是0->1->2->3->4这样的,如果我们中间执行一个previous方法,那么是这样的:(next取数)0->(next取数)1->(previous方法)1->(next取数)2->(next取数)3->(next取数)4,重复取出了一个1,于是取出了6个数。

        public void set(E e) {
            if (lastRet < 0)
                throw new IllegalStateException();
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            try {
                ArrayList.this.set(lastRet, e);
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

set方法,熟悉的两重if判断,然后调用ArrayList自己的set方法去设置元素内容。但是有一个问题,cursor的值是在ListItr里面设置的,而lastRet的值在Itr里面就已经设置成为了-1,那么如果我建立了一个ListItr之后,立马使用set方法,肯定第一个if判断都过不去。我的理解是,ListItr并不是最后真正的迭代器,它应该还有一个子类。

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

add方法,在cursor指向的下标索引位置添加一个元素内容。调用ArrayList自己的add方法,在调用了add方法之后cursor+1,也就是说,如果我指着第一个元素调用add方法,当调用完了之后,cursor指着的就是第二个元素了。然后lastRet就回到了它的出生点。ListItr内部类里面的方法就讲完了。

    /**
     * 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.
     *
     * 

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: *

     *      list.subList(from, to).clear();
     * 
* 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. * *

The semantics of the list returned by this method become undefined if * the backing list (i.e., this list) is structurally modified 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 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 + ")"); }

我们又回到了ArrayList的内部,subList这个方法和protected void removeRange(int fromIndex, int toIndex)这个方法有点像,都是有一个开始下标索引和结束下标索引。首先调用了一个subListRangeCheck方法

subListRangeCheck方法的作用,就是专门抛出异常,如果你传递进来的fromIndex和toIndex有不对的地方,直接给你报错。如果你传递进来的参数没问题,那么它会新建一个内部类SubList并返回给你。

subList是比较常用的一个方法,比如,一个长度为10内容为0123456789的内容,当我使用subList(2,5)的时候,它会将下标索引为2也就是第三个元素开始,到下标索引为5也就是第六个元素这之间的内容,以List的形式拿取出来。于是就得到了:0156789

SubList是ArrayList的一个内部类

subList的返回值是一个list,说明SubList这个类肯定是一个List列表,既然是列表一样的东西,那肯定会和ArrayList一样有各种各样的增加,移除,修改方法,所以这个SubList代码贼长。

    private class SubList extends AbstractList implements RandomAccess {
        private final AbstractList parent;
        private final int parentOffset;
        private final int offset;
        int size;
        SubList(AbstractList 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) {
            if (index < 0 || index >= this.size)
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
            if (ArrayList.this.modCount != this.modCount)
                throw new ConcurrentModificationException();
            E oldValue = (E) ArrayList.this.elementData[offset + index];
            ArrayList.this.elementData[offset + index] = e;
            return oldValue;
        }
        public E get(int index) {
            if (index < 0 || index >= this.size)
              throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
            if (ArrayList.this.modCount != this.modCount)
                throw new ConcurrentModificationException();
            return (E) ArrayList.this.elementData[offset + index];
        }
        public int size() {
            if (ArrayList.this.modCount != this.modCount)
                throw new ConcurrentModificationException();
            return this.size;
        }
        public void add(int index, E e) {
            if (index < 0 || index > this.size)
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
            if (ArrayList.this.modCount != this.modCount)
                throw new ConcurrentModificationException();
            parent.add(parentOffset + index, e);
            this.modCount = parent.modCount;
            this.size++;
        }
        public E remove(int index) {
            if (index < 0 || index >= this.size)
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
            if (ArrayList.this.modCount != this.modCount)
                throw new ConcurrentModificationException();
            E result = parent.remove(parentOffset + index);
            this.modCount = parent.modCount;
            this.size--;
            return result;
        }
        protected void removeRange(int fromIndex, int toIndex) {
            if (ArrayList.this.modCount != this.modCount)
                throw new ConcurrentModificationException();
            parent.removeRange(parentOffset + fromIndex,
                               parentOffset + toIndex);
            this.modCount = parent.modCount;
            this.size -= toIndex - fromIndex;
        }
        public boolean addAll(Collection c) {
            return addAll(this.size, c);
        }
        public boolean addAll(int index, Collection c) {
            if (index < 0 || index > this.size)
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
            int cSize = c.size();
            if (cSize==0)
                return false;
            if (ArrayList.this.modCount != this.modCount)
                throw new ConcurrentModificationException();
            parent.addAll(parentOffset + index, c);
            this.modCount = parent.modCount;
            this.size += cSize;
            return true;
        }
        public Iterator iterator() {
            return listIterator();
        }
        public ListIterator listIterator(final int index) {
            if (ArrayList.this.modCount != this.modCount)
                throw new ConcurrentModificationException();
            if (index < 0 || index > this.size)
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
            final int offset = this.offset;
            return new ListIterator() {
                int cursor = index;
                int lastRet = -1;
                int expectedModCount = ArrayList.this.modCount;
                public boolean hasNext() {
                    return cursor != SubList.this.size;
                }
                @SuppressWarnings("unchecked")
                public E next() {
                    if (expectedModCount != ArrayList.this.modCount)
                        throw new ConcurrentModificationException();
                    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() {
                    if (expectedModCount != ArrayList.this.modCount)
                        throw new ConcurrentModificationException();
                    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 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;
                    if (expectedModCount != ArrayList.this.modCount)
                        throw new ConcurrentModificationException();
                }
                public int nextIndex() {
                    return cursor;
                }
                public int previousIndex() {
                    return cursor - 1;
                }
                public void remove() {
                    if (lastRet < 0)
                        throw new IllegalStateException();
                    if (expectedModCount != ArrayList.this.modCount)
                        throw new ConcurrentModificationException();
                    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();
                    if (expectedModCount != ArrayList.this.modCount)
                        throw new ConcurrentModificationException();
                    try {
                        ArrayList.this.set(offset + lastRet, e);
                    } catch (IndexOutOfBoundsException ex) {
                        throw new ConcurrentModificationException();
                    }
                }
                public void add(E e) {
                    if (expectedModCount != ArrayList.this.modCount)
                        throw new ConcurrentModificationException();
                    try {
                        int i = cursor;
                        SubList.this.add(i, e);
                        cursor = i + 1;
                        lastRet = -1;
                        expectedModCount = ArrayList.this.modCount;
                    } catch (IndexOutOfBoundsException ex) {
                        throw new ConcurrentModificationException();
                    }
                }
            };
        }
        public List subList(int fromIndex, int toIndex) {
            subListRangeCheck(fromIndex, toIndex, size);
            return new SubList(this, offset, fromIndex, toIndex);
        }
        private String outOfBoundsMsg(int index) {
            return "Index: "+index+", Size: "+this.size;
        }
        public Spliterator spliterator() {
            if (modCount != ArrayList.this.modCount)
                throw new ConcurrentModificationException();
            return new ArrayListSpliterator(ArrayList.this, offset,
                                               offset + this.size, this.modCount);
        }
    }

在贴上源码之后,逐步对它进行理解,首先从定义的变量开始:

        private final AbstractList parent;
        private final int parentOffset;
        private final int offset;
        int size

第一个变量很好理解,因为SubList就从别的List里面进行操作,这个parent就相当于将要被操作的对象。

第二个变量,parent里面的偏移量,在实例化SubList的时候,就将fromIndex赋予给了parentOffset。

第三个变量offset,自身的偏移量或者说是增加量,应该是用于记录从fromIndex开始移动了多少。

第四个变量size,这个指的是被取出的长度。

接下来看构造方法就明白了。

        SubList(AbstractList 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;
        }

第五个this记录的是modCount,为了确保操作的数据是最新数据,在后面的方法中应该会用到这个变量。

        public E set(int index, E e) {
            if (index < 0 || index >= this.size)
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
            if (ArrayList.this.modCount != this.modCount)
                throw new ConcurrentModificationException();
            E oldValue = (E) ArrayList.this.elementData[offset + index];
            ArrayList.this.elementData[offset + index] = e;
            return oldValue;
        }

首先看set方法,和ArrayList自身的set方法差不多,实现的原理都大同小异。不过,这个index比较的size不是ArrayList定义的size,而是SubList自己定义的size。因为set修改的并不是ArrayList里面的数据,而是提取出来部分的数据。

比如10个长度内容为0123456789的数据,使用SubList取出了123456,那么这个set方法修改的是123456下的index指着的元素内容。但是,set方法并没有像之前一样使用某一个变量存储ArrayList里面的elementData,而是直接从里面读取。假如你使用这个set方法,传递index=2进去。那么修改的是123456里面的下标索引为2也就是第三个元素3的值。而由于是直接从ArrayList的数据里面读取,如果不设置偏移量,直接传递index=2,那么取出来的将是0123456789里面的下标索引为2的元素也就是2这个值。

所以offset的作用就体现出来了,set方法的index是相对于ArrayList里面的数据偏移了多少,所以才有offset+index。

        public E get(int index) {
            if (index < 0 || index >= this.size)
              throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
            if (ArrayList.this.modCount != this.modCount)
                throw new ConcurrentModificationException();
            return (E) ArrayList.this.elementData[offset + index];
        }
        public int size() {
            if (ArrayList.this.modCount != this.modCount)
                throw new ConcurrentModificationException();
            return this.size;
        }
       

在理解了offset的意思之后,后面的get方法是一样的理解。

offset这个变量名字只在set和get方法和后面的迭代器Iterator中使用,也就是说,offset是在不影响数据长度的情况下使用。也就是说SubList这个方法的第二个参数,实际上影响的是你更改值和取值时候的位置。所以offset更多的解释是偏移量,offset>0就是往右偏移来取值,相反<0就是往左偏移来取值。

比如同样是这个数据0123456789操作,我使用SubList里面的get方法取index=2位置的值,但我的offset设置成了1,那我取到的值就不是2了而变成了3;同样的道理,如果offset设置成了-1,那么取到的值就不是2而变成了1.

        public E remove(int index) {
            if (index < 0 || index >= this.size)
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
            if (ArrayList.this.modCount != this.modCount)
                throw new ConcurrentModificationException();
            E result = parent.remove(parentOffset + index);
            this.modCount = parent.modCount;
            this.size--;
            return result;
        }
        protected void removeRange(int fromIndex, int toIndex) {
            if (ArrayList.this.modCount != this.modCount)
                throw new ConcurrentModificationException();
            parent.removeRange(parentOffset + fromIndex,
                               parentOffset + toIndex);
            this.modCount = parent.modCount;
            this.size -= toIndex - fromIndex;
        }
        public boolean addAll(Collection c) {
            return addAll(this.size, c);
        }
        public boolean addAll(int index, Collection c) {
            if (index < 0 || index > this.size)
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
            int cSize = c.size();
            if (cSize==0)
                return false;
            if (ArrayList.this.modCount != this.modCount)
                throw new ConcurrentModificationException();
            parent.addAll(parentOffset + index, c);
            this.modCount = parent.modCount;
            this.size += cSize;
            return true;
        }

后面的remove和add方法,用一个例子就很好解释了。同样拿0123456789来说,SubList得到的数据是123456

首先使用SubList里面的add方法,此时index=2,要加入的值是9,那么对于SubList来说,变化是这样的:1293456。对于ArrayList里面的数据来说,变化是这样的:01293456789。我们可以得到,在使用SubList的add方法的时候,实际上使用的依然是ArrayList本身的add方法;SubList的长度发生了变化,ArrayList的长度也发生了变化,都增加了1.

addAll,和相应的remove方法也是同样的道理。

那么SubList的用处在哪里呢?我们之前第一次看到SubList的时候是在

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

这个方法里面,这是ArrayList的方法,也就是可以通过这样使用:

    ArrayList a=new ArrayList<>(某个数据);//假设数据是0123456789
    a.sublist(2,5).add(1,4);

这里只假设了10个数据,但是如果这个数据非常的庞大,可能不止10个可能是100个1000个呢?此时如果直接使用ArrayList的方法去修改,只要你的index看走眼了写错了,直接GG。但是当你使用SubList的时候就简单了,你有1000个数据是吧?我用sublist方法先把[60,80)这一段给我框出来,然后我在框出来的数据基础上修改,这样,当我设置的index走眼了或者超出了的时候,sublist就会直接反馈给我,而不需要去看那一大堆的1000个数据了。

后续还有SubList自己的一个迭代器的实现,方法和Itr里面的方法差不多,只不过多了一个offset偏移量,就不多解释什么了。

        public Iterator iterator() {
            return listIterator();
        }
        public ListIterator listIterator(final int index) {
            if (ArrayList.this.modCount != this.modCount)
                throw new ConcurrentModificationException();
            if (index < 0 || index > this.size)
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
            final int offset = this.offset;
            return new ListIterator() {
                int cursor = index;
                int lastRet = -1;
                int expectedModCount = ArrayList.this.modCount;
                public boolean hasNext() {
                    return cursor != SubList.this.size;
                }
                @SuppressWarnings("unchecked")
                public E next() {
                    if (expectedModCount != ArrayList.this.modCount)
                        throw new ConcurrentModificationException();
                    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() {
                    if (expectedModCount != ArrayList.this.modCount)
                        throw new ConcurrentModificationException();
                    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 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;
                    if (expectedModCount != ArrayList.this.modCount)
                        throw new ConcurrentModificationException();
                }
                public int nextIndex() {
                    return cursor;
                }
                public int previousIndex() {
                    return cursor - 1;
                }
                public void remove() {
                    if (lastRet < 0)
                        throw new IllegalStateException();
                    if (expectedModCount != ArrayList.this.modCount)
                        throw new ConcurrentModificationException();
                    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();
                    if (expectedModCount != ArrayList.this.modCount)
                        throw new ConcurrentModificationException();
                    try {
                        ArrayList.this.set(offset + lastRet, e);
                    } catch (IndexOutOfBoundsException ex) {
                        throw new ConcurrentModificationException();
                    }
                }
                public void add(E e) {
                    if (expectedModCount != ArrayList.this.modCount)
                        throw new ConcurrentModificationException();
                    try {
                        int i = cursor;
                        SubList.this.add(i, e);
                        cursor = i + 1;
                        lastRet = -1;
                        expectedModCount = ArrayList.this.modCount;
                    } catch (IndexOutOfBoundsException ex) {
                        throw new ConcurrentModificationException();
                    }
                }
            };
        }

除了这些,SubList还有三个方法:

        public List subList(int fromIndex, int toIndex) {
            subListRangeCheck(fromIndex, toIndex, size);
            return new SubList(this, offset, fromIndex, toIndex);
        }
        private String outOfBoundsMsg(int index) {
            return "Index: "+index+", Size: "+this.size;
        }
        public Spliterator spliterator() {
            if (modCount != ArrayList.this.modCount)
                throw new ConcurrentModificationException();
            return new ArrayListSpliterator(ArrayList.this, offset,
                                               offset + this.size, this.modCount);
        }

第一个方法呢,就是返回一个新的SubList。因为返回的本来就是一个list列表,只要列表里面的数足够大,自然也可以框选出一块更小的list。

第二个方法呢,在ArrayList里面见过了,就是为了告诉我们,你设置的index是这个值,但是size只有这么一点大。这个方法用在抛出异常的时候,也就是throw的时候。

第三个方法,Spliterator是在API24的时候添加进来的。具体的说明如下:

An object for traversing and partitioning elements of a source. The source of elements covered by a Spliterator could be, for example, an array, a Collection, an IO channel, or a generator function.

翻译过来的意思应该是,这个方法是区分,你的这个数据是来自于数组还是列表还是IO流或者是其他来源。 

总结:

sublist本质上修改的依然是ArrayList里面的数据,虽然看起来多次一举,实际上可以很好的保护数据。使用sublist的时候,我们都会自己定义一个数组去存储sublist返回的值,这样就不会影响到ArrayList的数了。

Iterator迭代器本身也不是很复杂,只要搞明白了cursor和lastRet的关系就好了。

你可能感兴趣的:(Android)