Chapter 8: Arrays and Dynamic Arrays
8.09Beginner / Intermediate6 topics14 min2 interactive animations

Java-specific arrays

The Java library tools for arrays: Arrays.copyOf, Arrays.fill, System.arraycopy, Arrays.equals, deep array methods and ArrayList's resizing behaviour, with the semantics and the traps of each.

Learning goals

  • Choose the right copy and fill method
  • Compare arrays by content
  • Handle nested arrays with the deep methods
  • Explain how ArrayList resizes

Prerequisites

Array fundamentalsCore operations
8.09.1

Arrays.copyOf

Arrays.copyOf(a, newLength) returns a new array of the given length: it pads with zeros (or null, false) when longer and truncates when shorter. copyOfRange(a, from, to) copies a slice, with to exclusive and allowed to exceed the length. Both are O(newLength).

Use them to grow a buffer or take a prefix or slice.

Java
1int[] a = {1, 2, 3, 4, 5};
2int[] longer = Arrays.copyOf(a, 7); // {1, 2, 3, 4, 5, 0, 0}
3int[] prefix = Arrays.copyOf(a, 3); // {1, 2, 3}
4int[] slice = Arrays.copyOfRange(a, 1, 4); // {2, 3, 4}
8.09.2

Arrays.fill

Arrays.fill(a, value) sets every element; Arrays.fill(a, from, to, value) sets a range with to exclusive. Common uses: initialise a distance array to a large value, or reset a counter array between test cases. For arrays of arrays, fill each row separately.

Do not fill a 2D array with one shared row: all rows would be the same object.

Java
1int[] dist = new int[6];
2Arrays.fill(dist, Integer.MAX_VALUE / 2); // large, but adding two of them cannot overflow
3int[][] grid = new int[3][4];
4for (int[] row : grid) Arrays.fill(row, -1); // each row separately
8.09.3

System.arraycopy

System.arraycopy(src, srcPos, dest, destPos, length) is a native block copy. It works correctly when source and destination are the same array with overlapping ranges, which makes it the tool for shifting elements in insert and delete. It throws if a range is out of bounds.

It is typically faster than a hand-written copy loop.

Java
1int[] a = {1, 2, 3, 4, 5, 0};
2System.arraycopy(a, 2, a, 3, 3); // shift a[2..4] right by one (overlap is safe)
3a[2] = 99; // {1, 2, 99, 3, 4, 5}
8.09.4

Arrays.equals

a.equals(b) on an array compares references, so two arrays with the same contents are not equal. Arrays.equals(a, b) compares length and elements. For nested arrays use Arrays.deepEquals. Arrays.hashCode pairs with Arrays.equals for use as a hash key, though a List or record is usually safer.

Printing an array directly shows its identity, not its values.

Java
1int[] a = {1, 2, 3}, b = {1, 2, 3};
2boolean ref = a.equals(b); // false: different objects
3boolean val = Arrays.equals(a, b); // true
4String text = Arrays.toString(a); // "[1, 2, 3]"
5int cmp = Arrays.compare(a, new int[]{1, 2, 4}); // negative: a is smaller
8.09.5

Deep arrays

Arrays of arrays need the deep variants: Arrays.deepToString, Arrays.deepEquals and Arrays.deepHashCode. clone() on a 2D array copies only the row references (a shallow copy); build a deep copy row by row.

Step through the shallow and deep copy cases in the animation.

Java
1int[][] g = {{1, 2}, {3, 4}};
2System.out.println(Arrays.deepToString(g)); // [[1, 2], [3, 4]]
3int[][] deep = new int[g.length][];
4for (int i = 0; i < g.length; i++) deep[i] = g[i].clone();
5boolean same = Arrays.deepEquals(g, deep); // true: equal contents, independent rows

Aliasing and copying arrays

Interactive · edit the input

Your input

Try

variables

a → @1

@1 int[]

100
201
302
403
Setup

new int[] creates one object on the heap; the variable a holds only a reference to it.

Step 1 / 4
Java
1int[] a = { 10, 20, 30, 40 }; // options 0 and 1 use this 1D array
2int[] b = a; // option 0: copies the reference only
3int[] b = a.clone(); // option 1: copies the elements
4int[][] a2 = { { 10, 20 }, { 30, 40 } }; // options 2 and 3 use this 2D array
5int[][] b2 = a2.clone(); // option 2: new outer array, SAME row objects
6int[][] b2 = Arrays.stream(a2).map(int[]::clone).toArray(int[][]::new); // option 3: rows copied too
7b[idx] = v; // (b2[0][idx] = v for options 2 and 3)
8System.out.println(Arrays.toString(a)); // does a see the change?

Live state

0 writes

a.length

4

No condition evaluated on this step
Execution trace (dry run table)Show 4 steps
StepLineStateWhat happens
1L1a.length=4new int[] creates one object on the heap; the variable a holds only a reference to it.
2L2same=trueb = a copies the reference, not the array. Both variables now point at the same object (@1).
3L7idx=1 v=99b[1] = 99 writes into the object b points at.
4L8a=[10, 99, 30, 40] b=[10, 99, 30, 40]a shows the change too ([10, 99, 30, 40]), because a and b are two names for one object.
8.09.6

ArrayList resizing and amortization

ArrayList keeps an Object[] buffer. An empty list starts with no buffer; the first add allocates 10 slots, and when the buffer is full it grows by about 50%: newCapacity = old + (old >> 1), giving 10, 15, 22, 33, ... Each growth copies the existing references, so n adds cost O(n) in total and every add is amortised O(1). ensureCapacity and the ArrayList(int) constructor avoid the intermediate copies; trimToSize releases the spare room.

Choose the ArrayList preset in the animation to see this growth sequence.

Java
1List<Integer> xs = new ArrayList<>();
2for (int i = 0; i < 100; i++) xs.add(i); // resizes at sizes 10, 15, 22, 33, 49, 73
3List<Integer> ys = new ArrayList<>(100); // one allocation, no resizes during the loop
4for (int i = 0; i < 100; i++) ys.add(i);

Dynamic array: capacity, growth and shrinking

Interactive · edit the input

Your input

Try

size elements in the buffer · length 0

Used slot (size)Spare capacity

data[] · capacity 1

0
Setup

A new dynamic array starts with capacity 1 and no elements.

Step 1 / 21
Java
1void add(int x) {
2 if (size == data.length) { // buffer is full
3 data = Arrays.copyOf(data, newCapacity()); // allocate bigger, copy size elements
4 }
5 data[size++] = x;
6}
7int removeLast() {
8 int x = data[--size];
9 if (size <= data.length / 4) data = Arrays.copyOf(data, Math.max(1, data.length / 2)); // optional shrink
10 return x;
11}

Live state

0 copies0 resizes

size

0

capacity

1

No condition evaluated on this step
Execution trace (dry run table)Show 21 steps
StepLineStateWhat happens
1L1size=0 capacity=1A new dynamic array starts with capacity 1 and no elements.
2L2size=0 capacity=1 x=4size 0 < capacity 1: there is a spare slot, so adding is O(1).
3L5size=1 capacity=1 x=4Write 4 into data[0] and increase size to 1.
4L2size=1 capacity=1 x=8size 1 equals capacity 1: no room for 8, so the buffer must grow.
5L3size=1 capacity=2Allocate capacity 2 and copy the 1 element (1 copy so far).
6L5size=2 capacity=2 x=8Write 8 into data[1] and increase size to 2.
7L2size=2 capacity=2 x=15size 2 equals capacity 2: no room for 15, so the buffer must grow.
8L3size=2 capacity=4Allocate capacity 4 and copy the 2 elements (3 copys so far).
9L5size=3 capacity=4 x=15Write 15 into data[2] and increase size to 3.
10L2size=3 capacity=4 x=16size 3 < capacity 4: there is a spare slot, so adding is O(1).
11L5size=4 capacity=4 x=16Write 16 into data[3] and increase size to 4.
12L2size=4 capacity=4 x=23size 4 equals capacity 4: no room for 23, so the buffer must grow.
13L3size=4 capacity=8Allocate capacity 8 and copy the 4 elements (7 copys so far).
14L5size=5 capacity=8 x=23Write 23 into data[4] and increase size to 5.
15L2size=5 capacity=8 x=42size 5 < capacity 8: there is a spare slot, so adding is O(1).
16L5size=6 capacity=8 x=42Write 42 into data[5] and increase size to 6.
17L2size=6 capacity=8 x=7size 6 < capacity 8: there is a spare slot, so adding is O(1).
18L5size=7 capacity=8 x=7Write 7 into data[6] and increase size to 7.
19L2size=7 capacity=8 x=9size 7 < capacity 8: there is a spare slot, so adding is O(1).
20L5size=8 capacity=8 x=9Write 9 into data[7] and increase size to 8.
21L11size=8 capacity=8 copies=7Final: size 8, capacity 8 (0 spare slots), 3 resizes that copied 7 elements in total. Doubling keeps total copies below 2n.

Practice ladder

Now try it yourself

Easy

  • Create a copy of {1, 2, 3} that is 5 long with copyOf
  • Why is a.equals(b) false for two arrays holding the same values?

Medium

  • Insert a value at index 2 of an int array using System.arraycopy
  • Explain why Arrays.fill on int[][] with one row object is a bug

Advanced

  • List the ArrayList capacities after 1, 11, 16, 23 and 34 adds

Key takeaways

  • copyOf grows or truncates, copyOfRange slices, fill initialises, arraycopy shifts safely.
  • Compare arrays with Arrays.equals or deepEquals, never with equals or ==.
  • ArrayList allocates 10 on first add and grows by 50%; presize when you can.