ArrayList的底層是由數組實現,所以所有的操作都是圍繞數組展開,要想理解add方法,就得先了解數組的增加,所以我們先實現一個數組的add,數組的添加可以從尾部增加或者其他位置插入,
如果在數組的尾部插入,只需要拿到數組的長度,直接在該索引處賦予元素值,下面自己手動簡單實現一個在數組任意位置實現數組元素添加:
public class MyArray { public static void main(String[] args) { /*創建一個數組*/ Object[] objectArray = new Object[10]; for (int i = 0; i < 10; i++) { objectArray[i] = i; } System.out.println("原數組"); for (int i = 0; i < objectArray.length; i++) { System.out.print(objectArray[i] + ","); } System.out.println(); System.out.println("插入后的數組"); Object[] newArray; try { newArray = MyArray.add(objectArray, 3, "hello"); for (int i = 0; i < newArray.length; i++) { System.out.print(newArray[i] + ","); } } catch (Exception e) { e.printStackTrace(); } } /*在一個數組的任意位置插入一個元素*/ public static Object[] add(Object[] objectArray, int index, Object object) throws Exception { if(index < 0 || index - objectArray.length > 0) { throw new Exception("數組索引無效" + index); } Object[] newObjectArray = new Object[objectArray.length]; /*首先將插入位置之前的所有元素拷貝到一個新的數組中*/ for (int i = 0; i < index; i++) { newObjectArray[i] = objectArray[i]; } /*然后將剩下的元素拷貝到插入位置加1后面的位置*/ for (int i = index + 1; i < objectArray.length; i++) { if(!"".equals(objectArray[i])) { newObjectArray[i] = objectArray[i - 1]; } } /*將新增的元素放到插入的位置*/ newObjectArray[index] = object; return newObjectArray; } }
(1) add方法
如果想在數組的任意位置插入元素,我們需要建立一個新的數組,將插入位置前面的元素拷貝到新數組中,將插入位置后面的元素的下標都后移一位,將插入位置騰出,
將需要插入的元素放入該位置,比起上面的demo,ArrayList的實現稍微復雜,在上述的過程中加入了擴容機制,也不會上面一樣將一個數組整個復制到另一個新數組中,
而是原來數組插入位置后面的元素按順序復制到原數組插入位置+1的位置,下面為ArrayList的add方法源碼:
public void add(int index, E element) { /*判斷插入的索引是否符合ArrayList范圍,在0 和 size之間,size是ArrayList實際元素個數,不包括底層數組的null元素*/ rangeCheckForAdd(index); /*擴容機制:判斷添加是否需要進行擴容*/ ensureCapacityInternal(size + 1); // Increments modCount!! /*將舊數組拷貝到一個新數組中,參數:被復制的原數組, 被復制數組的第幾個元素開始復制, 復制的目標數組, 從目標數組index + 1位置開始粘貼, 復制的元素個數,*/ System.arraycopy(elementData, index, elementData, index + 1, size - index); /*將新元素賦予該下標*/ elementData[index] = element; /*元素個數+1*/ size++; }
(2) addAll()方法
ArrayList的addAll()方法的實現和add()方法實現思路一致,只不過需要移動的元素更多,由於數組結構的特性,導致這樣的操作對於數據大的ArrayList的插入操作,
會嚴重影響代碼執行的效率,所以開發中我們應該盡量避免出現對數據元素多的ArrayList頻繁add。
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); /*數組長度+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; /*如果插入位置不在尾部,則移動原數組index以后的元素,未插入c騰出空間,如果在尾部,與addAll(Collection<? extends E> c)方法相同*/ if (numMoved > 0) System.arraycopy(elementData, index, elementData, index + numNew, numMoved); /*將需要插入的數組插入到騰出空間中*/ System.arraycopy(a, 0, elementData, index, numNew); /*長度+numNew*/ size += numNew; return numNew != 0; }