首先都不知道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,如下:
上面的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,但其裡面包含的重點還是
可以多加琢磨囉!
因此就自己以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,但其裡面包含的重點還是
可以多加琢磨囉!
留言
張貼留言