帶你走進Java集合_ArrayList原始碼深入分析4
上一篇我們主要講解了ArrayList的迭代器,我們首先歸納一下ArrayList迭代器的主要內容:
1.迭代器主要利用遊標cursor來遍歷集合的,遊標cursor主要指向下一個元素的下標。所以cursor是關鍵。
2.迭代器在迭代的時候可以察覺到fast-fail.
3.Itr的遊標只能向後移動,所以只能向後遍歷,而ListIterator既可以向前移動也可以向後移動
這一篇文章我們從原始碼角度講解ArrayList的最後一個知識點:SubList
從字面上可以知道是ArrayList的子元素,所以SubList也會提供刪、改、查,迭代的功能,我們要牢記一個知識點:subList不是從ArrayList複製一份,而是SubList指向的例項是ArrayList的一段對映,ArrayList的修改和SubList的修改是對同一個底層陣列的修改
public List<E> subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size);
return new SubList(this, 0, fromIndex, toIndex);
}
上面的方法有兩個引數,fromIndex是對映的開始下標,toIndex是對映的結束下標。其中0<=fromIndex<=toIndex<=size,此方法最後一個元素不包含toIndex,如果fromIndex,toIndex不符合
舉例說明:
public static void main(String[] args) throws Exception { List<Integer> list = new ArrayList<Integer>(); list.add(1); list.add(2); list.add(3); list.add(4); list.add(5); list.add(6); list.add(7); List<Integer> subList = list.subList(1, 4); for (Integer sub : subList) { System.out.print(sub + " "); } }
執行結果如下:
從運算結果中我們可以看到,subList方法包含fromIndex,但是不包含toIndex.
如果fromIndex、toIndex不符合0<=fromIndex<=toIndex<=size公式時,運算的結果是怎樣的,例如我們formIndex=1,toIndex=10,運算結果:
所以,呼叫ArrayList的subList(fromIndex,toIndex)方法時,要時刻記住0<=fromIndex<=toIndex<=size這個公式。
我總結了SubList有一下兩個特性:
特性1.SubList是ArrayList集合的一段對映,而不是拷貝。
特性2.要牢記這個公式:0<=fromIndex<=toIndex<=size
現在我們從SubList的原始碼來分析上面的的兩個特性
SubList是ArrayList的一個內部類,
1.SubList的重要屬性如下:
第一個重要的屬性:AbstractList<E> parent:這個就是ArrayList
第二個重要的屬性:int parentOffset:對映到ArrayList的開始下標
第三個重要的屬性:int offset:subList的開始下標,其實在ArrayList中parentOffset=offset.從下面原始碼可以證明:
public List<E> subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size);
return new SubList(this, 0, fromIndex, toIndex);
}
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;
}
引數offset=0,所以parentOffset=offset
SubList提供瞭如下方法,總結一下,呼叫這些方法時,都不能修改ArrayList,否則就會丟擲異常。每一個方法都會首先呼叫checkForComodification()檢查一下:
private void checkForComodification() {
if (ArrayList.this.modCount != this.modCount)
throw new ConcurrentModificationException();
}
第一個方法:E set(int index, E e)
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;
}
1)rangeCheck(index)就是判斷給出的索引是否有效
2)checkForComodification()就是判斷呼叫set的時候是否修改的ArrayList元素。
3)從第三句可以看出,直接修改ArrayList集合的元素
從這個方法中就可以證明特性1所說的,SubList是ArrayList一段對映,而不是複製。
下面的方法和set類似,只要讀過ArrayList的同學都不難理解,在這裡就不做解釋了。
這篇文章主要介紹了ArrayList中的一個方法subList(fromIndex,toIndex),我們記住SubList的兩個特性後,就能夠駕馭subList方法了
特性1.SubList是ArrayList集合的一段對映,而不是拷貝。
特性2.要牢記這個公式:0<=fromIndex<=toIndex<=size