Lesson 04 · 9 min read · Java for placements

Arrays, and the Arrays utility class

Fixed length and default values, jagged arrays, why Arrays.sort uses two different algorithms, and the copy and equality methods people get wrong.

An array in Java is an object with a fixed length, and almost every array bug comes from one of those two words.

Declaring and creating

int[] marks;                          // a reference, currently null
marks = new int[5];                   // length 5, all zeros
int[] scores = new int[] {87, 92, 78};
int[] short_form = {87, 92, 78};      // only valid at the declaration

int[] marks is the preferred spelling. int marks[] compiles — it is inherited from C — but puts type information in two places and reads worse.

Elements get a default value, never garbage:

Element type Default
int, long, short, byte 0
double, float 0.0
char '\u0000' — the null character, not a space
boolean false
any object type null

That last row is the source of an everyday NullPointerException:

String[] names = new String[3];
System.out.println(names[0]);            // null — printed fine
System.out.println(names[0].length());   // NullPointerException

Length is fixed, and it is a field

int[] xs = {1, 2, 3};
System.out.println(xs.length);        // 3 — a FIELD, no brackets
System.out.println("abc".length());   // 3 — a METHOD on String

length for arrays, length() for strings, size() for collections. Three spellings for one idea, and it is one of those things you simply have to memorise.

You cannot resize an array. To grow one, allocate a bigger one and copy:

int[] bigger = Arrays.copyOf(xs, xs.length * 2);   // extra slots are 0

That is exactly what ArrayList does for you internally, which is the answer to "how does ArrayList grow?" — it holds an array, and when it fills up it allocates a larger one (typically about 1.5×) and copies.

Indexing out of bounds throws rather than reading adjacent memory:

int[] xs = new int[3];
xs[3] = 1;              // ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
xs[-1] = 1;             // same exception

This is a real difference from C, and one of Java's headline safety properties.

Iterating

for (int i = 0; i < xs.length; i++) {      // when you need the index
    System.out.println(i + ": " + xs[i]);
}

for (int x : xs) {                         // enhanced for — cleaner when you do not
    System.out.println(x);
}

The enhanced for gives you a copy of each element for primitives, so assigning to the loop variable changes nothing:

for (int x : xs) {
    x = 0;              // modifies the copy — xs is untouched
}

To modify the array, you need the index. For an array of objects, the loop variable is a copy of the reference, so calling a mutating method on it does affect the object — the same distinction as passing an object to a method.

Two-dimensional arrays

int[][] grid = new int[3][4];               // 3 rows, 4 columns, all 0
int[][] fixed = {{1, 2}, {3, 4}, {5, 6}};

System.out.println(grid.length);            // 3 — number of rows
System.out.println(grid[0].length);         // 4 — length of the first row

for (int r = 0; r < grid.length; r++) {
    for (int c = 0; c < grid[r].length; c++) {
        grid[r][c] = r * 10 + c;
    }
}

A 2-D array in Java is an array of arrays, not a rectangular block. So rows can have different lengths — a jagged array:

int[][] jagged = new int[3][];        // rows not allocated yet
jagged[0] = new int[2];
jagged[1] = new int[5];
jagged[2] = new int[1];

Note grid[r].length rather than grid[0].length inside the loop. It costs nothing and it is correct for jagged input.

The Arrays utility class

import java.util.Arrays;

int[] xs = {5, 2, 8, 1};

Arrays.sort(xs);                          // in place, ascending
System.out.println(Arrays.toString(xs));  // [1, 2, 5, 8]

Arrays.fill(xs, 7);                       // every element 7
int[] part = Arrays.copyOfRange(xs, 1, 3);      // indices 1..2
int found = Arrays.binarySearch(xs, 5);         // requires a SORTED array
boolean same = Arrays.equals(xs, new int[]{7, 7, 7, 7});
int[][] g = {{1}, {2}};
System.out.println(Arrays.deepToString(g));     // [[1], [2]]

Four traps in that short list.

System.out.println(xs) prints garbage. An array does not override toString, so you get [I@1b6d3586 — the type and a hash. Use Arrays.toString, or Arrays.deepToString for 2-D.

xs == ys compares references. Arrays.equals compares contents element by element, and Arrays.deepEquals recurses into nested arrays.

Arrays.sort uses two different algorithms, and this is a favourite question:

  • For primitives — a dual-pivot quicksort. Average O(n log n), in place, not stable. Stability is irrelevant for primitives, since two equal ints are indistinguishable.
  • For objects — TimSort, a merge sort variant. O(n log n) guaranteed, stable, needs O(n) extra space. Stability matters here, because two objects can be equal by the comparator and still be different objects.

Arrays.sort cannot sort primitives in descending order. There is no comparator overload for int[]. Your options:

Integer[] boxed = {5, 2, 8};
Arrays.sort(boxed, Collections.reverseOrder());     // works — objects

int[] xs = {5, 2, 8};
Arrays.sort(xs);                                    // ascending, then reverse manually
for (int i = 0, j = xs.length - 1; i < j; i++, j--) {
    int t = xs[i]; xs[i] = xs[j]; xs[j] = t;
}

Sorting objects by a field, which is the everyday case:

String[] names = {"banana", "kiwi", "apple"};
Arrays.sort(names);                                          // alphabetical
Arrays.sort(names, Comparator.comparingInt(String::length)); // by length
Arrays.sort(names, Comparator.reverseOrder());               // reverse alphabetical

Copying, and the shallow-copy trap

int[] a = {1, 2, 3};

int[] b = a;                          // NOT a copy — a second reference
int[] c = a.clone();                  // a copy
int[] d = Arrays.copyOf(a, a.length); // a copy
int[] e = new int[a.length];
System.arraycopy(a, 0, e, 0, a.length);   // a copy, fastest for large arrays

b = a gives you two names for one array, exactly as in Python. b[0] = 9 changes a[0].

And clone() on a 2-D array is shallow — it copies the array of row references, not the rows:

int[][] grid = {{1, 2}, {3, 4}};
int[][] copy = grid.clone();
copy[0][0] = 9;
System.out.println(grid[0][0]);       // 9 — the original changed

int[][] deep = new int[grid.length][];
for (int r = 0; r < grid.length; r++) {
    deep[r] = grid[r].clone();        // copy each row
}

Arrays versus ArrayList

Array ArrayList
Size fixed at creation grows automatically
Holds primitives or objects objects only (boxing for primitives)
Length xs.length list.size()
Read/write by index xs[i] get(i) / set(i, v)
Insert in the middle manual shifting add(i, v), O(n)
Memory lower — no boxing, no headroom higher

Use an array when the size is known and the elements are primitives, which in a coding round is often. Use ArrayList when the size changes.

One conversion trap worth knowing:

Integer[] boxed = {1, 2, 3};
List<Integer> list = Arrays.asList(boxed);       // fixed-size VIEW of the array
list.add(4);                                     // UnsupportedOperationException
list.set(0, 9);                                  // allowed — and it changes boxed[0]

List<Integer> real = new ArrayList<>(Arrays.asList(boxed));   // an independent list

Arrays.asList returns a fixed-size list backed by the array. It is not an ArrayList, and it does not copy.

What to take into an interview

  • An array's length is fixed at creation and read as a field, xs.length.
  • Elements default to 0 / false / '\u0000' / null — never garbage.
  • Out-of-bounds access throws ArrayIndexOutOfBoundsException.
  • A 2-D array is an array of arrays, so it can be jagged. Use grid[r].length.
  • Arrays.toString to print, Arrays.equals to compare contents.
  • Arrays.sort is dual-pivot quicksort for primitives (not stable) and TimSort for objects (stable).
  • There is no descending sort for int[] — box it, or reverse afterwards.
  • clone() on a 2-D array is shallow; copy each row.
  • Arrays.asList gives a fixed-size view, not an ArrayList.
Lesson 4 of 12 · all 12 are free to read, no account. Course contents