An object array is a fixed-size sequence of objects:
def a= new Object[4] //we must specify the size of the fixed-size array assert a.size() == 4 assert a.length == 4 //field alternative to size() a.each{ assert it == null } //default value is null assert a instanceof Object[] assert a.class == Object[] a[0]= 'a' a[1]= 2 //elements can be any value a.putAt(2, 'c') //alternative method name syntax a[3]= false assert a[0] == 'a' && a[1] == 2 && a.getAt(2) == 'c' && a.getAt(3) == false //either subscript or method name assert a[-4] == 'a' && a[-3] == 2 && a[-2] == 'c' && a[-1] == false //subscripts can be negative try{ a[4]; assert 0 } catch(e){ assert e instanceof ArrayIndexOutOfBoundsException } try{ a[-5]; assert 0 } catch(e){ assert e instanceof ArrayIndexOutOfBoundsException } assert a[1..2] == [2, 'c'] //we can use the same subscripting as for lists assert a[2..2] == ['c'] assert a[0, 2..3] == ['a', 'c', false] assert a.toList() == ['a', 2, 'c', false] assert a as List == ['a', 2, 'c', false] assert a.toArrayString() == '{"a", 2, "c", false}'
The subscript used in constructing object arrays is evaluated as an integer:
assert new Object[ 0x100000003 ].size() == 3 //index coerced to integer, positive or negative try{ new Object[ 0x80000000 ]; assert 0 } catch(e){ assert e instanceof NegativeArraySizeException }
We can specify the initial collection of contained objects when we construct the array. Those objects can be any other entity in Groovy, eg, numbers, boolean values, characters, strings, regexes, lists, maps, closures, expandos, classes, class instances, or even other object arrays:
assert [ 14.25, 17g, [1,2,3], 'Hello, world', ['a', false, null, 5] as Object[], new Object[200], { it*it }, ArrayList, ] as Object[]
We can make a shallow copy using clone():
def aq= [1,2] assert ([ aq, 3 ] as Object[]).clone()[0].is( aq ) //clone() makes a shallow copy only
We have a special syntax for constructing multi-dimensional object arrays with null initial values:
assert [ new Object[3], new Object[2], new Object[1] ] as Object[] //usual syntax assert [ new Object[3], new Object[3], new Object[3] ] as Object[] //usual syntax when each constituent array of equal size def m= new Object[3][3] //special syntax when each constituent array of equal size (0..<m.size()).each{i-> (0..<m[i].size()).each{j-> assert m[i][j] == null //we can also subscript with special syntax using consecutive indexes } }
We must specify the size of at least the first, outermost, dimension of an object array when we first create it:
//ar= new Object[] //compile error when uncommented ar= new Object[10][] ar= new Object[10][][] ar= new Object[10][10][]
A multidimensional array need not have arrays of the same length at each level. Thus, a triangular matrix may be created by:
def triangle= new Object[100][] (0..<triangle.length).each{ triangle[it] = new Object[it+1] }
There are strict rules concerning evaluation when subscripting object arrays:
class MyException extends Exception{} def exception(){ throw new MyException() } def i, a, b i= 4 a= new Object[i][i=3] //first subscript evaluated before next one assert a.size() == 4 && a[0].size() == 3 a= [ 11, 12, 13, 14 ] as Object[] b= [ 3, 2, 1, 0 ] as Object[] assert a[(a=b)[2]] == 12 //outside of subscript evaluated before inside, ie, a[b[2]] or a[1] or 12 i= 1 //if what's outside subscript throws exception, subscript isn't evaluated try{ exception()[i=2] }catch(e){ assert i == 1 } i= 1 a= new Object[2][2] //if subscript evaluation throws exception, subscripts to right not evaluated try{ a[ exception() ][i=2] }catch(e){ assert i == 1 } //index evaluated before indexing occurs (including checking whether //what's outside subscript is null)... a= null try{ a[exception()]; assert 0 }catch(e){ assert e instanceof MyException } //NullPointerException never occurs here i= 1 try{ a[i=2]; assert 0 } catch(e){ assert i == 2 && e instanceof NullPointerException }
Implementing an ArrayList with an Object Array
ArrayLists are implemented with object arrays internally. Each ArrayList instance has a capacity, the size of a fixed-size array used to store the elements. This array is always at least as large as the list size, and its capacity grows automatically as elements are added to the list. To see the internal capacity of lists constructed with various values:
class Extras{
static enq(List l){ l.elementData.size() }
}
def measure= { list, times->
def sizes= []
times.times{
def size
use(Extras){ size= list.enq() }
(size - list.size() + 1).times{ list << 'a' }
sizes << size
}
sizes
}
def list1= new ArrayList()
def measure1= measure(list1, 10)
assert measure1 == [10, 16, 25, 38, 58, 88, 133, 200, 301, 452]
def list2= new ArrayList(10)
def measure2= measure(list2, 10)
assert measure2 == measure1
def list3= new ArrayList(5)
def measure3= measure(list3, 10)
assert measure3 == [5, 8, 13, 20, 31, 47, 71, 107, 161, 242]
def list4= []
def measure4= measure(list4, 10)
assert measure4 == [0, 1, 2, 4, 7, 11, 17, 26, 40, 61]
def list5= new ArrayList(0)
def measure5= measure(list5, 10)
assert measure5 == measure4
For efficiency, we can increase the capacity of a list before adding a large number of elements:
class Extras{ static enq(List l){l.elementData.size()} }
use(Extras){
list= []
list.ensureCapacity(200)
assert list.enq() == 200
list<< 'a'<< 'b'<< 'c'
assert list.enq() == 200
list.trimToSize()
//we can also trim the internal fixed-size array to the list size
assert list.enq() == 3
}
We can see how many times a list has been modified:
list= []<< 'a' << 'b'; assert list.modCount == 2 list.remove('a'); assert list.modCount == 3






