add 陣列越界_ArrayList原始碼解讀二之add、set、get、remove
技術標籤:add 陣列越界
在看add、set原始碼之前,我們先看幾個重要的函式,add、set、remove、get都會呼叫它。
private void ensureCapacityInternal(int minCapacity) {//add、set、remove、get先都會呼叫此方法 ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); }//minCapacity是新增元素後陣列大小
private static int calculateCapacity(Object[] elementData, int minCapacity) {//獲取陣列大小 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//建立無參構造器時候會把DEFAULTCAPACITY_EMPTY_ELEMENTDATA指向elementData return Math.max(DEFAULT_CAPACITY, minCapacity); }//當建立無參構造時候才會有用到,預設值為10 return minCapacity; }
private void ensureExplicitCapacity(int minCapacity) { modCount++;//記錄修改次數 if (minCapacity - elementData.length > 0)//當新增元素後陣列大小大於原來陣列大小長度 grow(minCapacity);//擴容函式 }
private void grow(int minCapacity) {//擴容函式 int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1);//擴容1.5倍 if (newCapacity - minCapacity < 0)//當新增元素後陣列大於擴容後的倍數時 newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0)//當陣列遠遠大於Array規範長度時候 newCapacity = hugeCapacity(minCapacity); elementData = Arrays.copyOf(elementData, newCapacity);//複製 }
- 一般情況進行擴容是1.5倍。
- 特殊情況:新增的元素後的數量遠超過擴容1.5倍的值時,會擴容新增元素的數量。
( 比如說:第一個ArrayList大小是10 第二個ArrayList大小為30 進行addALL函式操作的時候minCapacity的大小是30 遠遠超過擴容1.5倍後的數量)
**注意!!!許多在講arrayList擴容機制的時候只會說1.5倍 而不說特殊情況。**
看懂這些方法後接下來到add、set、get、remove函式就容易了。
**(相比add方法)set、get、remove函式可以選擇性看!!!!!!!!**
###1.ArrayList中的add函式。
####add函式
public boolean add(E e) { ensureCapacityInternal(size + 1); //進行擴容機制 elementData[size++] = e;//進行賦值 return true; }
public void add(int index, E element) { rangeCheckForAdd(index); ensureCapacityInternal(size + 1); System.arraycopy(elementData, index, elementData, index + 1,size - index); elementData[index] = element; size++; }
add 2個方法基本操作差不多
1. rangeCheckForAdd是判斷index是否超過elementData的大小,是則丟擲越界異常。
2. ensureCapacityInternal是上面提到判斷呼叫的函式,最主要是進行擴容機制。
3. System.arraycopy是為直接原陣列index後面的值往後移一位如圖顯示。
4. 賦值。
5. 記錄元素數量,並且+1。
移動陣列操作
###2.ArrayList中的set函式。
####set函式
public E set(int index, E element) { rangeCheck(index);//是否檢查越界 E oldValue = elementData(index); elementData[index] = element; return oldValue; }
- 首先獲取到elementData的index舊元素
- 將新的element值賦予index
- 返回給OldValue**
###3.ArrayList中的get函式。
####get函式
public E get(int index) { rangeCheck(index); return elementData(index); }
**1. 獲取到element(index)的位置元素返回。**
###4.ArrayList中的remove函式。
####remove函式
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; return oldValue; }
- 首先獲取到elementData的index舊元素
- 獲取index後面需要移動的位置
- System.arraycopy進行移動(與addAll差不多)
- 對空出來的元素進行賦值null值
- 返回舊值
結論:
- 無參構造在第一次新增元素時候進行擴容後容量會是10。
- 擴容機制一般情況是1.5倍,特殊情況(新增元素大於擴容1.5倍的時候)是擴容為新增元素本身大小。
- 指定位置index操作元素時候都會進行越界檢查、並且會對陣列進行移動操作。