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,如下:
  1. class DynamicArray<E>{
  2. private Object data[];
  3. private int size;
  4. public DynamicArray(){
  5. data = new Object[0];
  6. size = data.length;
  7. }
  8. public int size(){
  9. return size;
  10. }
  11. public E remove(int index){
  12. if(index >= size){
  13. throw new IndexOutOfBoundsException();
  14. }
  15. int moveNum = size - index - 1;
  16. E removeValue = this.get(index);
  17. System.arraycopy(data, index+1, data, index, moveNum);
  18. //wait garbage collector to collect
  19. data[--size] = null; 
  20. return removeValue;
  21. }
  22. public void add(E e){
  23. //assign data's reference to old_data
  24. Object old_data = data;
  25. data = new Object[++size];
  26. data[size-1] = e;
  27. //copy old_data value to data array, from 0 to old_data.length
  28. System.arraycopy(old_data, 0, data, 0, size-1);
  29. //release old_data memory(wait garbage collector to collect)
  30. old_data = null;
  31. }
  32. @SuppressWarnings("unchecked")
  33. public E get(int index){
  34. if(index >= size){
  35. throw new IndexOutOfBoundsException();
  36. }
  37. return (E) data[index];
  38. }
  39. @Override
  40. public String toString() {
  41. return Arrays.toString(data);
  42. }
  43. }

上面的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,但其裡面包含的重點還是

可以多加琢磨囉!

留言