程式扎記: [ Doc ] JN1025-Arrays

標籤

2014年2月5日 星期三

[ Doc ] JN1025-Arrays

來源自 這裡
Preface:
一個 Object 陣列為一個固定長度的 Object 序列:
  1. def a= new Object[4//we must specify the size of the fixed-size array  
  2. assert a.size() == 4  
  3. assert a.length == 4 //field alternative to size()  
  4. a.each{ assert it == null } //default value is null  
  5. assert a instanceof Object[]  
  6. assert a.class == Object[]  
  7.   
  8. a[0]= 'a'  
  9. a[1]= 2 //elements can be any value  
  10. a.putAt(2'c'//alternative method name syntax  
  11. a[3]= false  
  12. assert a[0] == 'a' && a[1] == 2 && a.getAt(2) == 'c' && a.getAt(3) == false  
  13.     //either subscript or method name  
  14. assert a[-4] == 'a' && a[-3] == 2 && a[-2] == 'c' && a[-1] == false  
  15.     //subscripts can be negative  
  16.   
  17. try{ a[4]; assert 0 }  
  18. catch(e){ assert e instanceof ArrayIndexOutOfBoundsException }  
  19. try{ a[-5]; assert 0 }  
  20. catch(e){ assert e instanceof ArrayIndexOutOfBoundsException }  
  21.   
  22. assert a[1..2] == [2'c'//we can use the same subscripting as for lists  
  23. assert a[2..2] == ['c']  
  24. assert a[02..3] == ['a''c'false]  
  25.   
  26. assert a.toList() == ['a'2'c'false]  
  27. assert a as List == ['a'2'c'false]  
  28. assert a.toArrayString() == '[a, 2, c, false]'  
在建立陣列過程中, 在 '[' 與 ']' 中的字符會被轉為 Integer 類型:
  1. assert new Object[ 0x100000003 ].size() == 3  
  2.     //index coerced to integer, positive or negative  
  3. trynew Object[ 0x80000000 ]; assert 0 }  
  4. catch(e){ assert e instanceof NegativeArraySizeException }  
當你使用 '[' 與 ']' 建立陣列時, 在 Groovy 是使用 ArrayList 來承接裡面給的東西. 但如果真的需要的是陣列, 可以透過 as 關鍵字轉型:
  1. def m = [1,'2',false]  
  2. assert m.class.getName() == "java.util.ArrayList"  
  3. m = [1,'2',false] as Object[]  // 轉成 Object 陣列!  
  4. assert m.class.name == "[Ljava.lang.Object;"  
當使用 clone() 進行物件複製時, 進行的是 shallow copy:
  1. class X{  
  2.     def name  
  3. }  
  4.   
  5. def x = new X(name:"John")  
  6. def aq= [1,2,x]  
  7. def bq = ([ aq, 3 ] as Object[]).clone()  
  8. assert bq[0].is( aq ) // 使用 is 來判斷是否指向同一個物件.  
  9. x.name = "Peter"  
  10. assert bq[0][2].name == "Peter"  // 因為是 shallow copy, 所以變更 x 會影響到 clone 後的物件  
底下是多維度的 Object 陣列宣告範例, 初始值為 null:
  1. assert [ new Object[3], new Object[2], new Object[1] ] as Object[]  
  2. //usual syntax  
  3. assert [ new Object[3], new Object[3], new Object[3] ] as Object[]  
  4. //usual syntax when each constituent array of equal size  
  5.   
  6. def m= new Object[3][3]  
  7. //special syntax when each constituent array of equal size  
  8. (0..<m.size()).each{i->  
  9.     (0..<m[i].size()).each{j->  
  10.         assert m[i][j] == null  
  11.         //we can also subscript with special syntax using consecutive indexes  
  12.     }  
  13. }  
底下是在進行陣列索引時的規則範例:
  1. class MyException extends Exception{}  
  2. def exception(){ throw new MyException() }  
  3. def i, a, b  
  4.   
  5. i= 4  
  6. a= new Object[i][i=3//first subscript evaluated before next one  
  7. assert a.size() == 4 && a[0].size() == 3  
  8.   
  9. a= [ 11121314 ] as Object[]  
  10. b= [ 3210 ] as Object[]  
  11. assert a[(a=b)[2]] == 12  
  12.     //outside of subscript evaluated before inside, ie, a[b[2]] or a[1] or 12  
  13.   
  14. i= 1 //if what's outside subscript throws exception, subscript isn't evaluated  
  15. try{ exception()[i=2] }catch(e){ assert i == 1 }  
  16.   
  17. i= 1  
  18. a= new Object[2][2]  
  19.   //if subscript evaluation throws exception, subscripts to right not evaluated  
  20. try{ a[ exception() ][i=2] }catch(e){ assert i == 1 }  
  21.   
  22. //index evaluated before indexing occurs (including checking whether   
  23. //what's outside subscript is null)...  
  24. a= null  
  25. try{ a[exception()]; assert 0 }catch(e){ assert e instanceof MyException }  
  26.     //NullPointerException never occurs here  
  27. i= 1  
  28. try{ a[i=2]; assert 0 }  
  29. catch(e){ assert i == 2 && e instanceof NullPointerException }  
Implementing an ArrayList with an Object Array:
ArrayList 是使用陣列實作的 Array, 而初始的陣列大小為 10. 當你不斷的往裡面添加元素時, 當原先的陣列不夠使用時則會擴充成更大的陣列 (size=10->size=16), 底下的範例代碼檢視這個行為:
  1. class Extras{  
  2.   static enq(List l){ l.elementData.size() }  
  3. }  
  4. def measure= { list, times->  
  5.   def sizes= []  
  6.   times.times{  
  7.     def size  
  8.     use(Extras){ size= list.enq() }  
  9.     printf "Size=$size;list.size()=%d\n", list.size()  
  10.     (size - list.size() + 1).times{ list << 'a' } // 故意加入 'a' 使原先的 list 剩餘空間不夠而必須進行 expand  
  11.     sizes << size  
  12.   }  
  13.   sizes  
  14. }  
  15.   
  16. def list1= new ArrayList()  
  17. def measure1= measure(list1, 10// 對 list1 進行 10 次檢視每次 expand 的狀況 .  
  18. assert measure1 == [101625385888133200301452]  
  19.   
  20. def list2= new ArrayList(10)  
  21. def measure2= measure(list2, 10)  
  22. assert measure2 == measure1  
  23.   
  24. def list3= new ArrayList(5)  
  25. def measure3= measure(list3, 10)  
  26. assert measure3 == [581320314771107161242]  
  27.   
  28. def list4= []  
  29. def measure4= measure(list4, 10)  
  30. assert measure4 == [012471117264061]  
  31.   
  32. def list5= new ArrayList(0)  
  33. def measure5= measure(list5, 10)  
  34. assert measure5 == measure4  
因為每次的陣列擴充的是時間的 cost, 因此當你已經知道要加入大量的元素前, 你可以先加大陣列的大小, 以避免不斷的陣列擴充造成的時間成本:
  1. class Extras{ static enq(List l){l.elementData.size()} }  
  2. use(Extras){  
  3.   list= []  
  4.   list.ensureCapacity(200)  // 初始陣列大小為 200  
  5.   assert list.enq() == 200  
  6.   list<< 'a'<< 'b'<< 'c'  
  7.   assert list.enq() == 200  
  8.   list.trimToSize()  
  9.       //we can also trim the internal fixed-size array to the list size  
  10.   assert list.enq() == 3  
  11. }  
Groovy 的 array 在變更次數 (添加/刪除 元素) 可以透過下面範例觀察:
  1. list= []<< 'a' << 'b'assert list.modCount == 2  
  2. list.remove('a'); assert list.modCount == 3  
Supplement:
Stackoverflow > How do I use groovy's AS keyword
Stackoverflow > Groovy type conversion
當你使用 as 關鍵字進行轉型時, 方法 asType 會被使用來完成轉型的動作. 參考下面範例代碼:
  1. class X{  
  2.     def name  
  3.     public asType(Class c) {  
  4.         if(c == Integer.classreturn name.length()  
  5.         if(c == String.classreturn name     
  6.     }  
  7. }  
  8.   
  9. def x1 = new X(name:"John") as String  
  10. assert x1 == "John"  
  11. def x2 = new X(name:"John") as Integer  
  12. assert x2 == 4  

This message was edited 16 times. Last update was at 06/02/2014 12:38:05

沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!