Arrays
What Arrays Are
An array in Java is a fixed-size, homogeneous, reference-type container that holds a sequence of elements of a single type, indexed from zero. Arrays are objects — they are allocated on the heap, and the variable holds a reference to the array object.
Declaration and Allocation
Arrays are declared by appending [] to the element type:
int[] numbers; // preferred style — type[] variable
String[] names; // an array of String references
Point[] points; // an array of Point references
The alternative C-style syntax (int a[]) is legal but discouraged — it places the brackets on the variable name, suggesting (misleadingly) that int a[], b declares two arrays, when in fact b is just an int.
A declaration does not create the array — it only declares a reference. To allocate storage:
int[] numbers = new int[5]; // array of 5 ints, each defaulting to 0
String[] names = new String[3]; // array of 3 references, each defaulting to null
Allocation zeroes or nulls the elements: numeric types get 0 (or 0.0), boolean gets false, char gets '\u0000', and reference types get null.
Length
Every array has a length field — note, not a method call, no parentheses:
int[] data = new int[10];
int size = data.length; // 10
length is final and cannot be changed. Once allocated, an array’s size is fixed for its lifetime. If you need a resizable sequence, use ArrayList.
Access and Mutation
Indexing is zero-based and uses square brackets:
int[] a = new int[3];
a[0] = 10;
a[1] = 20;
a[2] = 30;
int x = a[0]; // 10
a[1] = a[2]; // copy element 2 into element 1
Accessing an index outside [0, length-1] throws an ArrayIndexOutOfBoundsException at runtime. The JVM performs bounds checking on every array access.
Allocation Options
Explicit Size with Default Values
int[] a = new int[5]; // {0, 0, 0, 0, 0}
String[] s = new String[3]; // {null, null, null}
Array Initialiser Syntax
int[] a = {1, 2, 3, 4, 5};
String[] days = {"Mon", "Tue", "Wed", "Thu", "Fri"};
This is only valid when declaring a variable (or as part of an anonymous array expression). It cannot be used after the variable is declared:
int[] a;
a = {1, 2, 3}; // COMPILE ERROR — initialiser only valid in declaration
a = new int[]{1, 2, 3}; // OK — anonymous array creation
Arrays Are Reference Types
This is one of the most important facts for the Tripos: an array variable holds a reference to the array object on the heap.
int[] a = {1, 2, 3};
int[] b = a;
Now a and b refer to the same array object. Changing b[0] is visible through a[0] — they are aliases.
b[0] = 99;
System.out.println(a[0]); // 99
Copying an Array
To get an independent copy, use Arrays.copyOf():
int[] a = {1, 2, 3};
int[] b = Arrays.copyOf(a, a.length); // new array with same values
b[0] = 99;
System.out.println(a[0]); // 1 — a is unaffected
System.arraycopy() provides low-level bulk copying. clone() creates a shallow copy (for arrays of primitives, this is fine; for arrays of references, the references are copied but the objects themselves are not duplicated).
Iterating Over Arrays
Index-Based For Loop
for (int i = 0; i < a.length; i++) {
System.out.println(a[i]);
}
Enhanced For Loop (For-Each)
for (int element : a) {
System.out.println(element);
}
The enhanced for loop is cleaner when you do not need the index. But you cannot modify the array contents through the loop variable (assigning to element changes the local copy, not the array element).
Multi-Dimensional Arrays
Java has no true multi-dimensional arrays. Instead, an “array of arrays” is used:
int[][] matrix = new int[3][4]; // 3 rows, each row is an int[4]
matrix is a reference to an array of int[] references, each of which refers to a row array. This means rows can have different lengths (jagged arrays):
int[][] triangle = new int[3][];
triangle[0] = new int[1];
triangle[1] = new int[2];
triangle[2] = new int[3];
Initialiser syntax for multi-dimensional arrays:
int[][] matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
Array Covariance
Java considers Dog[] to be a subtype of Animal[] (if Dog extends Animal). This is called array covariance and is a known design flaw — it permits code that compiles but fails at runtime:
Dog[] dogs = new Dog[3];
Animal[] animals = dogs; // OK — arrays are covariant
animals[0] = new Cat(); // COMPILES but throws ArrayStoreException at runtime
The JVM inserts a runtime check when storing into an array of reference type to enforce that the element is actually compatible with the array’s component type. This issue is discussed more thoroughly in the generics notes, but the key takeaway: prefer ArrayList<Dog> over Dog[] when you need collection-style operations.
Common Tripos Traps
- Mutating through an alias: if two references point to the same array, a mutation through one is visible through the other — trace carefully in “what does this print” questions
- length is a field, not a method:
a.length()is a compile error;a.lengthis correct - Default values: uninitialised array elements have default values (
0,false,null) — do not assume they contain anything meaningful - Off-by-one: iterate from
0toa.length - 1, not toa.length - Null array elements: arrays of reference types are initially filled with
null, and calling a method ona[i]will throw aNullPointerExceptionif that element was never assigned