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的內容我就不說了推薦一下這篇文章,講的很詳細
ArrayList原始碼分析(下)——Java8中新增的Spliterator的分析
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/231473.html
標籤:其他
下一篇:vulnhub potato
