Java - Use System.arraycopy make basic Dynamic Array

首先都不知道Java source code 內的ArrayList是利用System.arraycopy製作的,到現在才知道!

因此就自己以System.arraycopy來製作簡易的版本,只有實現主要的三項功能,即add、get、

remove function。

一開始是在讀大陸翻譯書,成為Java終極高手的16個關鍵碼的Java記憶體回收章節內,有

提到在ArrayList remove的部分,講到array remove掉一個項目,最後需指向null,如此就可

以等待垃圾收集器回收!以此才不會浪費heap記憶體區塊的空間。就是這個片段看到了原來

Java ArrayList remove function是這樣做的,所以索性就自己動動手了。

下面為小弟自己寫的DynamicArray class,如下:
class DynamicArray<E>{
   private Object data[];
 
   private int size;
 
   public DynamicArray(){
      data = new Object[0];
      size = data.length;
   }
 
   public int size(){
      return size;
   }
 
   public E remove(int index){
      if(index >= size){
         throw new IndexOutOfBoundsException();
      }
      int moveNum = size - index - 1;
      E removeValue = this.get(index);
      System.arraycopy(data, index+1, data, index, moveNum);
      //wait garbage collector to collect
      data[--size] = null; 
      return removeValue;
   }
 
   public void add(E e){
      //assign data's reference to old_data
      Object old_data = data; 
      data = new Object[++size];
      data[size-1] = e;
      //copy old_data value to data array, from 0 to old_data.length
      System.arraycopy(old_data, 0, data, 0, size-1); 
      //release old_data memory(wait garbage collector to collect)
      old_data = null; 
   }
 
   @SuppressWarnings("unchecked")
   public E get(int index){
      if(index >= size){
         throw new IndexOutOfBoundsException();
      }
      return (E) data[index];
   }

   @Override
   public String toString() {
      return Arrays.toString(data);
   }
}

上面的DynamicArray class的使用方式與ArrayList相同,一開始需指定一個型態給他

DynamicArray<String> myStr = new DynamicArray<String>();

此時會初始化,Object data成員變數,並且assign size 變數大小。

接著進行add的動作,如下:

myStr.add("Hello Java!");
myStr.add("Hello World!");
myStr.add("Hello Everybody!");

當您第一次add,就需要將data的reference assign給另外宣告的變數old_data,如此一來

當new Object[++size]給data時,old_data才保有原本的reference address。

再來就是將add進的entity assign給新的data[0]位置,接著要做舊的data資料copy給新的data陣

列。

而由於一開始old_data本身無資料,因此size-1 = 0,及表示copy 0筆資料過去XD

接著將原有的old_data address 指向null,當沒有人指向這個address,垃圾收集器就會回收!

以此類推...

再來是remove的部分,如下:

System.out.println("remove index 0:"+mystrarray.remove(0));

當您remove掉,第一筆資料時(從0開始算)

相關過程如下圖



size - index - 1 => 3 - 0 - 1 = 2

表示得移動當筆要刪除資料的後面兩筆資料,此時複製index 1, index 2去覆蓋掉

index 0, index 1的資料,最後只要將data[--size] = null,就可以將size遞減一 => 2

data[--size] => data[2] = null

PS. 此時,如果去執行下面的這行,會印出[Hello World!, Hello Everybody!, null]

System.out.println(myStr);

但是call size() function 會得到2,由於return size;

因此在這邊toString function內再濾過null的data不印,如此可能才合理!

畢竟在remove的地方,我們沒有重新new一個新的Object array,因此此成員變數的實際

長度不會改變!

當然ArrayList還有實作很多function,還是使用官方的好XD,但其裡面包含的重點還是

可以多加琢磨囉!

留言