JAVA集合之ArrayList源码解析
本人想写博客很久了,这是我的第一篇博客,之后我也会陆陆续续的把JAVA的集合篇补全,废话不多说,让我们开始曹飞ArrayList(1.8JDK)。
继承关系
在上图我们可以看到ArrayList的继承关系和优缺点
- 排序有序,可重复
- 底层使用数组
- 读取速度快,增删速度慢
- 线程不安全
- 按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>>10。
transient 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的内容我就不说了推荐一下这篇文章,讲的很详细