1. 程式人生 > 其它 >add 陣列越界_ArrayList原始碼解讀二之add、set、get、remove

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。

53cbcc6abc6a2a2312a5c5eca512ebce.png

移動陣列操作

###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操作元素時候都會進行越界檢查、並且會對陣列進行移動操作。