之前了解了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 extends E> c) {
return addAll(this.size, c);
}
public boolean addAll(int index, Collection extends E> 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 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;
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 extends E> c) {
return addAll(this.size, c);
}
public boolean addAll(int index, Collection extends E> 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 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;
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的关系就好了。