Skip to content
Part IA Michaelmas Term

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.length is correct
  • Default values: uninitialised array elements have default values (0, false, null) — do not assume they contain anything meaningful
  • Off-by-one: iterate from 0 to a.length - 1, not to a.length
  • Null array elements: arrays of reference types are initially filled with null, and calling a method on a[i] will throw a NullPointerException if that element was never assigned