ArrayList的刪除實現其實就是和數組添加相反的一個過程,只不過刪一個元素和刪除多個元素的實現方式略有區別,但是思路還是一樣,如下圖:
一、remove方法
如上,移除一個元素時,可以通過元素或者元素的索引移除,有四個步驟:
(1)判斷索引index是否越界
(2)將 index + 1 及之后的元素向前移動一位
(3)最后一個值變為null
(4)長度size - 1
將該索引以后的元素下標前移,最后一個元素置為NULL,源碼如下:
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); /*將最后一個元素置空,然后GC機制會回收該內存,並且ArrayList的長度-1*/ elementData[--size] = null; return oldValue; }
public boolean remove(Object o) { /*如果刪除的元素對象為null*/ if (o == null) { /*刪除ArrayList中第一個為null的元素*/ for (int index = 0; index < size; index++) if (elementData[index] == null) { fastRemove(index); return true; } } else { /*刪除ArrayList中匹配到的第一個元素*/ for (int index = 0; index < size; index++) if (o.equals(elementData[index])) { fastRemove(index); return true; } } return false; } /*不進行索引驗證,直接刪除*/ private void fastRemove(int index) { modCount++; 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 }
二、removeAll方法
removeAll的實現方式雖然在思路上和前面一致,但是代碼實現略有不同,在移除多個元素時,會遍歷數組,先去將數組中的每個元素一一和移除元素數組里的元素匹配,
如圖:
當移除完成后,會將最后幾位(和移除元素數組長度相同)的元素置為null,源碼如下:
public boolean removeAll(Collection<?> c) { /*驗證刪除Collection是否為null,若null則拋出NullPointerException*/ Objects.requireNonNull(c); return batchRemove(c, false); } 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 { /*r != size 說明元素未完全匹配完,則將未匹配的size - r個元素粘貼到w以后的位置*/ if (r != size) { System.arraycopy(elementData, r, elementData, w, size - r); w += size - r; } if (w != size) { /*將移除完成w以后的元素置為null,由GC回收內存*/ for (int i = w; i < size; i++) elementData[i] = null; modCount += size - w; /*數組長度置為w*/ size = w; modified = true; } } return modified; }
三、clear方法
clear方法也是ArrayList的刪除方法之一,只不過是清除所有元素,所以只要將所有元素置為null,由GC回收內存即可
public void clear() { /*記錄集合得修改次數*/ modCount++; /*將每個元素置空,之后,內存會被GC回收*/ for (int i = 0; i < size; i++) elementData[i] = null; /*元素個數置為0*/ size = 0; }
上面刪除操作,我們發現,元素是沒了,但是數組的長度並沒有變,那么ArrayList有沒有自動縮容機制了,答案是沒有,但是它提供可以實現縮容的方法,我們可以手動去觸發:
/** 將數組容量縮小至元素數量 */ public void trimToSize() { modCount++; if (size < elementData.length) { elementData = (size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size); } }