Command Palette

Search for a command to run...

PHASE 3Beginner ~33 min· topic 8 of 11

Topic 3.8

Arrays

In one line

An array is a fixed-size, numbered row of values of one type, stored together as a single object on the heap. You reach each value by its index, from 0 to length - 1, in constant time.

Think of it like this

A row of numbered post-office boxes. There are exactly 10 boxes, numbered 0 to 9, all the same size, side by side. To get a letter you don't search; you go straight to box 7. You can change what's inside a box, but you can't add an eleventh box to the row. For more boxes you'd need a new, bigger row and to move every letter across.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

Array
A fixed-size, numbered sequence of values of one type, stored as one object.
Element
One value stored in an array.
Index
The position number of an element. The first is 0, the last is length - 1.
Length
How many elements an array has, read with arr.length. It's fixed when the array is created.
Default value
The value an element has before you assign one: 0, 0.0, false, the zero char, or null.
Array initializer
Braces with values, {2, 3, 5}, that create an array with those elements and the matching length.
Alias
A second variable referring to the same array. Changes through one are visible through the other.
Out of bounds
An index below 0 or at least length. Using one throws ArrayIndexOutOfBoundsException.
Shallow copy
A copy of the array itself. For arrays of objects it copies the references, not the objects they point to.

Step by step

01Why arrays: one name for many values

To store five test scores you could write score1, score2... score5. But then you can't loop over them, and 500 scores would need 500 variables.

An array gives one name to the whole group and a number to each slot, so a loop can visit every element: for (int i = 0; i < scores.length; i++).

02Declaring and creating

There are two steps, often written on one line. Declare a variable of an array type: int[] scores; (the brackets belong to the type). Create the array object: scores = new int[5];.

Or use an initializer when you know the values: String[] days = {"Mon", "Tue", "Wed"};. The longer form new String[] {"Mon", "Tue"} works anywhere, including as a method argument or return value.

Java also accepts the C-style int scores[], but int[] scores is the standard style: it keeps the whole type in one place.

Main.javawhole filejava
int[] scores = new int[5];                  // [0, 0, 0, 0, 0]
String[] names = new String[3];             // [null, null, null]
int[] primes = {2, 3, 5, 7, 11};            // length 5
double[] prices = new double[] {9.5, 12.0}; // works in any expression
int[] empty = new int[0];                   // legal: length 0

03Indexes and length

Indexes start at 0 because an index is really an offset from the start of the array: element i is i steps from the first one. That's how the JVM finds any element in one step: start address + i times the element size.

length is a field, not a method: scores.length, never scores.length() (that's for String). The last valid index is always length - 1, so loops use i < arr.length, not <=.

Indexes and lengthdiagram
Rendering diagram…

04Every access is checked

In C, reading past the end of an array silently reads whatever memory is next, a huge source of crashes and security holes. Java checks every index at run time and throws ArrayIndexOutOfBoundsException with the bad index and the length.

The check is cheap, and the JIT removes it when it can prove a loop's index stays in range (called range check elimination), which is one more reason to write the standard for (int i = 0; i < arr.length; i++) loop.

Creating an array with a negative length fails too: new int[-1] throws NegativeArraySizeException: -1.

05Looping over arrays

Use the index loop when you need the position or want to change elements: for (int i = 0; i < arr.length; i++) arr[i] *= 2;.

Use the enhanced for loop (Topic 2.7) when you only read values: for (int s : scores) sum += s;. Assigning to s inside it changes only the loop variable, not the array.

06Assignment shares, copying duplicates

int[] b = a; copies the reference, so both names lead to one array: b[0] = 100 changes a[0] too. This is the aliasing you saw in Topic 3.3.

To get an independent array, copy it: a.clone() (same length), Arrays.copyOf(a, newLength) (pads with defaults or truncates), or System.arraycopy(src, srcPos, dest, destPos, count) to copy part of one array into another.

Arrays can't grow. "Growing" means creating a bigger array and copying the old elements in, which is exactly what ArrayList does for you when it fills up (Topic 9.2).

07Arrays are objects with a type

Every array is an object whose class is created by the JVM: int[] has the internal name [I, String[] is [Ljava.lang.String;, and int[][] is [[I. That's what you see when you print an array directly: [I@87aac27 is the type name, @, and a hash code in hex.

Object arrays are covariant: a String[] can be assigned to an Object[] variable. That's convenient but unsafe, so the JVM checks every store into an object array at run time and throws ArrayStoreException if the type is wrong. Generic collections (Phase 8) avoid this hole.

Try it yourself

  1. 1

    Reverse an array in place

    Write a loop that swaps arr[i] with arr[arr.length - 1 - i] for i up to the middle. Predict what happens with an odd length (the middle element stays put), then run it on {1, 2, 3, 4, 5} and print with Arrays.toString.

  2. 2

    Print an array the wrong way

    Add System.out.println(scores); to the first example. You'll see something like [I@87aac27, and the part after @ changes between runs. Replace it with Arrays.toString(scores) (add import java.util.Arrays;).

  3. 3

    Grow an array by hand

    Start with int[] data = {1, 2, 3};. Write the three lines that "add" a 4: make a new array one longer, copy, set the last element, and point data at the new array. This is what ArrayList.add does when full.

Code & diagrams

Create, fill, loop, summarise New tab
Sign in to run this example in your browser.

Expected output

defaults: 0 0.0 false null
length = 5
sum = 402, average = 80.4, max = 95
last prime = 11
2 3 5 7 11
Aliases vs copies, == vs Arrays.equals New tab
Sign in to run this example in your browser.

Expected output

a     = [100, 2, 3]
alias = [100, 2, 3]
copy  = [1, 2, 3]
a == alias: true
a == lookalike: false
Arrays.equals(a, lookalike): true
bigger = [100, 2, 3, 0, 0]
dest   = [0, 100, 2, 3, 0]
Arrays are objects: type names and ArrayStoreException New tab
Sign in to run this example in your browser.

Expected output

[I
[Ljava.lang.String;
[[I
ArrayStoreException: java.lang.Integer
NegativeArraySizeException: -1

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Loop with <= instead of <

Write i <= scores.length in the loop condition.

Main.javawhole filejava
public class Main {
    public static void main(String[] args) {
        int[] scores = {90, 85, 70, 60, 95};
        for (int i = 0; i <= scores.length; i++) {
            System.out.println(scores[i]);
        }
    }
}
terminal
$ java Main
── what you'll see ──
90
85
70
60
95
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5
at Main.main(Main.java:5)

Break #2

Call length() on an array

Write arr.length() as you would for a String.

Main.javawhole filejava
int[] a = {1};
int x = a.length();
terminal
$ javac Main.java
── what you'll see ──
Main.java:5: error: cannot find symbol
int x = a.length();
^
symbol: method length()
location: variable a of type int[]
1 error

Break #3

Print an array directly

Write System.out.println(scores);.

terminal
$ java Main
── what you'll see ──
[I@87aac27
The hex part differs from run to run.

Myth vs fact

Myth

int[] b = a; makes a copy of the array.

Fact

It copies the reference. Both names refer to the same array. Use clone() or Arrays.copyOf to copy.

Myth

Arrays can grow when you add elements.

Fact

Their length is fixed forever. "Growing" means allocating a bigger array and copying, which ArrayList does automatically.

Myth

a == b compares array contents.

Fact

It compares references. Arrays.equals(a, b) compares contents element by element.

Myth

Array elements are uninitialised garbage like in C.

Fact

Every element starts at its default value: 0, false, the zero char or null.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    On 64-bit HotSpot with compressed class pointers, an array object has a 16-byte header (12-byte object header plus a 4-byte length), then the elements, rounded up to a multiple of 8 bytes. So new int[1000] is 4016 bytes, while an Integer[1000] holding distinct values costs 4016 bytes of references plus 16 bytes per Integer object. JDK 25 can shrink object headers further with -XX:+UseCompactObjectHeaders.

  • ▸

    The maximum length is a little under Integer.MAX_VALUE because of header space. Asking for new long[Integer.MAX_VALUE] fails with OutOfMemoryError: Requested array size exceeds VM limit regardless of heap size.

  • ▸

    Array covariance (String[] is an Object[]) is why every store into an object array needs a run-time type check, and why you can't create generic arrays like new T[10]. Collections chose the opposite rule: List<String> is not a List<Object> (Topic 8.5).

  • ▸

    Arrays of primitives store values contiguously, which makes scanning them very cache-friendly. An Integer[] or List<Integer> stores references to objects scattered around the heap, which can be several times slower to scan and much larger. For number crunching, prefer primitive arrays.

Remember this

  1. 1

    An array holds a fixed number of elements, all of one type: int[] scores = new int[5]; makes room for five ints. The number of elements is its length, read with scores.length (a field, no brackets), and it can't change after creation.

  2. 2

    Elements are numbered by index, starting at 0. The first is scores[0], the last is scores[scores.length - 1]. Using any other index throws ArrayIndexOutOfBoundsException at run time: Java checks every access.

  3. 3

    new fills a fresh array with default values: 0 for numbers, false for boolean, the character with code 0 for char, and null for object types like String. With an array initializer, int[] primes = {2, 3, 5, 7};, you choose the values and Java counts the length.

  4. 4

    An array is an object on the heap, and the variable holds a reference to it (Topic 3.3). So int[] b = a; doesn't copy anything: a and b are two names for one array. To copy, use a.clone(), Arrays.copyOf(a, n) or System.arraycopy.

  5. 5

    Because arrays are objects, == asks *same array?*, not *same contents?*, and printing one shows something like [I@87aac27 (its type code and a hash). Use Arrays.equals(a, b) and Arrays.toString(a) instead (Topic 3.10).

  6. 6

    Arrays are the foundation of almost every data structure: ArrayList (Topic 9.2), HashMap (Topic 9.4) and ArrayDeque are built on arrays inside. The DSA course's Arrays module (/dsa/arrays) is where you put them to work on problems.

Explain it without notes

01

Why do array indexes start at 0, and what is the valid index range of an array?

02

What happens in memory when you write int[] b = a;, and how do you make a real copy?

03

What does System.out.println(arr) print and why? How do you print the contents?

04

What is array covariance, and what run-time error can it cause?

Practice

01

Write a program that counts how many numbers in {4, -2, 7, 0, -5, 3} are positive, negative and zero.

02

Write static int indexOf(int[] arr, int target) that returns the first index of target, or -1. Test with {5, 8, 2, 8} and targets 8 and 9.

03

Write static int[] reversed(int[] arr) that returns a new reversed array, leaving the input unchanged. Print both.

04

Write a program that shifts every element of {1, 2, 3, 4, 5} one place to the left, moving the first element to the end, giving [2, 3, 4, 5, 1].

Trade-offs

  • ↔

    Arrays give the fastest possible indexed access and the most compact storage, but their size is fixed. When the number of items changes, an ArrayList handles resizing for you at a small cost.

  • ↔

    Primitive arrays (int[]) are compact and fast; object arrays and collections of wrappers (Integer[], List<Integer>) are more flexible but use several times more memory.

  • ↔

    Sharing an array between methods avoids copying but invites accidental changes. Copy at boundaries when the data must not change.

Done when you can

  • Done when you can create arrays with new and with initializers, and know their default values.

  • Done when you can loop over an array with both loop styles without going out of bounds.

  • Done when you can explain why int[] b = a; doesn't copy and make a real copy.

  • Done when you can compare and print arrays correctly with Arrays.equals and Arrays.toString.

  • Done when you can read an ArrayIndexOutOfBoundsException and fix it.