2011年11月20日

Java 源代碼分析系列 - ArrayList remove(Object object)


  public boolean remove(Object paramObject)
  {
    int i;
    if (paramObject == null)
      for (i = 0; i < this.size; ++i)
      {
        if (this.elementData[i] != null)
          continue;
        fastRemove(i);
        return true;
      }
    else
      for (i = 0; i < this.size; ++i)
      {
        if (!(paramObject.equals(this.elementData[i])))
          continue;
        fastRemove(i);
        return true;
      }
    return false;
  }

從代碼可以看到,remove這個方法可以刪除目標之object物件,並且可以使用它來刪除我們陣列null值,null刪除與非null刪除使用不同的判斷式來完成。
當迴圈中找到刪除目標時,會呼叫fastRemove(int)這個方法將該位置的元素刪除,fastRemove這個方法與ArrayList.remove(int)方法極為相似(參考Java - ArrayList remove(int pst)),但fastRemove如其名,式快速的刪除,因此裡面並沒有多餘的判斷(超出大小等),即沒有回傳值。代碼如下:

  private void fastRemove(int paramInt)
  {
    this.modCount += 1;
    int i = this.size - paramInt - 1;
    if (i > 0)
      System.arraycopy(this.elementData, paramInt + 1, this.elementData, paramInt, i);
    this.elementData[(--this.size)] = null;
  }


欲刪除paramInt位置











使用System.arraycopy(this.elementData, paramInt + 1, this.elementData, paramInt, i);將剩餘的陣列連接起來














 +







該方法會將欲刪除部分之後(黃色)陣列連接到原來陣列欲刪除的位置(紅色)上。











this.elementData[(--this.size)] = null;
刪除最後一個元素












Java 源代碼分析系列 - ArrayList remove(int pst)


  public E remove(int paramInt)
  {
    RangeCheck(paramInt);
    this.modCount += 1;
    Object localObject = this.elementData[paramInt];
    int i = this.size - paramInt - 1;
    if (i > 0)
      System.arraycopy(this.elementData, paramInt + 1, this.elementData, paramInt, i);
    this.elementData[(--this.size)] = null;
    return localObject;
  }


  private void RangeCheck(int paramInt)
  {
    if (paramInt < this.size)
      return;
    throw new IndexOutOfBoundsException("Index: " + paramInt + ", Size: " + this.size);
  }

首先必須先確定使用者要刪除的位置是否有超出陣列範圍,這裡使用RangeCheck(int)來檢查,若是超出範圍則會丟出IndexOutOfBoundsException例外。

如果範圍合理沒有超出範圍,這時候會算出刪除位置後所剩下的元素個數,接著使用System.arraycopy()這個方法將欲刪除元素後的所有元素加入到欲刪除的位置上。
實際操作如下面圖解:

欲刪除紅色











使用System.arraycopy(this.elementData, paramInt + 1, this.elementData, paramInt, i);將剩餘的陣列連接起來














 +







該方法會將欲刪除部分之後(黃色)陣列連接到原來陣列欲刪除的位置(紅色)上。











this.elementData[(--this.size)] = null;
刪除最後一個元素










return localObject;
回傳值為取代後,位置pst上的新元素。






下一篇 :  Java 源代碼分析系列 - ArrayList remove(Object object)



Java 源代碼分析系列 - ArrayList add()


  public boolean add(E paramE)
  {
    ensureCapacity(this.size + 1);
    this.elementData[(this.size++)] = paramE;
    return true;
  }


首先可以看到add這個方法的參數是以E開頭,表示該參數可以是任何的類別。
ensureCapacity方法用來確認容量是否足以加入新的節點。
  public void ensureCapacity(int paramInt)
  {
    this.modCount += 1;
    int i = this.elementData.length;
    if (paramInt <= i)
      return;
    Object[] arrayOfObject = this.elementData;
    int j = i * 3 / 2 + 1;
    if (j < paramInt)
      j = paramInt;
    this.elementData = Arrays.copyOf(this.elementData, j);
  }
這段比較有趣的地方是,j = i * 3 / 2 + 1這段,可以看出配置空間的動作並不是每次配置一次(+1)的方式,而是以這個公式去新增,一次可能配出許多個空間預留給下次的加入。
比如說現在List中有10個元素,當我們要加入第十一個元素時,11會被傳入ensureCapacity方法,可以看到if (paramInt <= i),明顯是大於的因此繼續執行,執行到j這行時,j = 11 * 3 / 2 + 1 = 16;因此系統在此時會把原本size10的陣列變成size16陣列,在ensureCapacity結束後,新的元素順利加入。

圖解 :
假設目前陣列長度 = 10










add(‘test’); // 11個元素
加入第11元素因為空間不夠,所組需要從新配置空間,陣列長度 = 16
















add(‘test’); // 12個元素
空間足夠,無須從新配置,直接加入。
















ShareThis