Free lesson · Java Basic To Advance
Arrays Basics
Java's First Container
An array is a fixed-size container holding values of the same type. Of all the data structures in Java, arrays are the most fundamental — every other collection (ArrayList, HashMap, HashSet) is built on top of arrays under the hood.
For interview prep, arrays appear in nearly every coding problem. Two-pointer techniques, sliding windows, dynamic programming tables, sort algorithms — all rely on arrays as the underlying storage. Mastering Java's array mechanics is foundational for everything that follows.
This Topic covers the basics: declaring arrays, creating them, accessing elements, the length property, and the most common pitfalls. The next four Topics drill into operations, multidimensional arrays, the Arrays utility class, and copying strategies.
I'm Olena, continuing through Module 4. Arrays are deceptively simple — the syntax is short but the mental model has corners that surprise people. We'll cover all of them.
Declaring an Array
There are two syntax forms for declaring an array variable. Both work; one is preferred:
int[] numbers; // ✓ preferred — brackets on the type
int numbers[]; // ✗ legal but discouraged — brackets on the variable
The first form makes it clearer that int[] is a type — an "array of int." The second form is a C-inherited syntax that Java permits but doesn't encourage. Almost all modern Java style guides recommend brackets on the type.
You can declare arrays of any type:
int[] scores;
double[] temperatures;
String[] names;
User[] users;
boolean[] flags;
int[][] grid; // 2D array (covered in Topic 4.3)
Declaring an array variable doesn't create the array. The variable starts as null (it's a reference type):
int[] numbers;
System.out.println(numbers); // null
System.out.println(numbers.length); // NullPointerException
You have to create the actual array before using it.
Creating an Array
Three ways to create an array:
1. Using new with a size:
int[] numbers = new int[5];
This creates an array of 5 ints. All elements are initialized to the default value for the type — 0 for numeric types, false for booleans, null for reference types.
int[] ints = new int[3]; // [0, 0, 0]
boolean[] bools = new boolean[3]; // [false, false, false]
String[] strs = new String[3]; // [null, null, null]
This is the most common way to create arrays when you know the size but not the contents.
2. Array literal:
int[] numbers = {1, 2, 3, 4, 5};
String[] names = {"Alice", "Bob", "Charlie"};
When you know both size and contents, the literal form is concise. Works only in the declaration — you can't assign a literal to an existing variable directly. For that, use the new-with-values form:
int[] numbers;
numbers = {1, 2, 3}; // ✗ compile error
numbers = new int[]{1, 2, 3}; // ✓ works
3. Using new with values:
int[] numbers = new int[]{1, 2, 3, 4, 5};
Works the same as the literal form but with the explicit type. Useful when you need to pass an array to a method without first storing it in a variable:
processNumbers(new int[]{1, 2, 3, 4, 5});
Accessing Elements
Arrays use zero-based indexing. The first element is at index 0, the last is at length - 1:
int[] numbers = {10, 20, 30, 40, 50};
System.out.println(numbers[0]); // 10
System.out.println(numbers[1]); // 20
System.out.println(numbers[4]); // 50
// numbers[5] would throw ArrayIndexOutOfBoundsException
To get the size of the array, use the length property:
int[] numbers = {10, 20, 30, 40, 50};
System.out.println(numbers.length); // 5
Note: length is a property of arrays (not a method). For arrays you write array.length. For Strings and other classes you write string.length() with parentheses. This inconsistency catches everyone at least once.
Iterating with the index:
int[] numbers = {10, 20, 30, 40, 50};
for (int i = 0; i < numbers.length; i++) {
System.out.println(i + ": " + numbers[i]);
}
Or with the enhanced for loop (covered in Topic 3.6) when you don't need the index:
for (int n : numbers) {
System.out.println(n);
}
graph TD
A[Array Lifecycle] --> B[Declaration<br/>int[] numbers]
B --> C[Variable exists<br/>but is null]
C --> D[Creation<br/>new int[5] or literal]
D --> E[Memory allocated<br/>elements at default values]
E --> F[Assignment<br/>numbers[0] = 10]
F --> G[Access<br/>read or modify]
style B fill:#dc2626,color:#fff
style D fill:#f59e0b,color:#fff
style F fill:#10b981,color:#fff
This diagram shows the lifecycle of a Java array. First comes declaration — int square-bracket-square-bracket numbers — which creates a variable but leaves it null. The array doesn't exist yet. Next comes creation, either with the new keyword and a size, or with a literal. This allocates memory in the heap and initializes elements to their default values. Then come assignment operations, where you set specific elements to specific values. And finally access — reading or modifying individual elements through indexing. Each stage is distinct, and skipping the creation step (using the variable while still null) produces NullPointerException.
Arrays Are Objects
A key concept: arrays are reference types, not primitives. The variable holds a reference to an array object stored in the heap. This has several consequences:
Assignment copies the reference, not the data:
int[] a = {1, 2, 3};
int[] b = a; // b refers to the SAME array
b[0] = 99;
System.out.println(a[0]); // 99 — both variables see the change
This is the same behavior we covered in Topic 2.3 for reference types. If you want a true copy of the array, you have to explicitly copy it (covered in Topic 4.5).
Arrays can be passed to methods:
public static void modifyArray(int[] arr) {
arr[0] = 100;
}
int[] numbers = {1, 2, 3};
modifyArray(numbers);
System.out.println(numbers[0]); // 100 — method modified the original
The method receives a reference to the same array. Modifications are visible to the caller. This is sometimes useful (in-place modification) and sometimes a bug (when you didn't intend to mutate the input).
Array equality uses references:
int[] a = {1, 2, 3};
int[] b = {1, 2, 3};
System.out.println(a == b); // false — different objects
System.out.println(a.equals(b)); // false — Array's equals is identity-based
System.out.println(Arrays.equals(a, b)); // true — Arrays utility compares content
To compare array contents, use Arrays.equals() (or Arrays.deepEquals() for nested arrays). Both == and .equals() on arrays compare references, which is rarely what you want.
Interactive animation: Assignment shares the array - b[0] = 99 shows up in a[0], and a method can change the caller's array.
Interactive animation: Two arrays holding {1, 2, 3} - == and .equals() both print false, and only Arrays.equals prints true.
Default Values
When you create an array with new and a size, all elements get default values:
| Type | Default |
|---|---|
byte, short, int, long |
0 |
float, double |
0.0 |
char |
'\u0000' (null character) |
boolean |
false |
| Reference types | null |
int[] counters = new int[100]; // 100 zeros
String[] names = new String[10]; // 10 nulls
boolean[] flags = new boolean[5]; // 5 falses
This is convenient — you don't have to manually initialize. It's also a hazard for reference arrays:
User[] users = new User[10];
users[0].getName(); // NullPointerException — users[0] is null
Reference arrays start full of nulls. You have to populate them before accessing.
Interactive animation: A new int[] starts full of usable zeros, while a new User[] starts full of nulls that throw NullPointerException.
Array Bounds
Accessing an index outside the array bounds throws ArrayIndexOutOfBoundsException at runtime:
int[] numbers = {1, 2, 3};
System.out.println(numbers[5]); // ArrayIndexOutOfBoundsException
System.out.println(numbers[-1]); // also ArrayIndexOutOfBoundsException
The exception is unchecked, so the compiler doesn't warn you. Bounds errors are runtime bugs, often caused by off-by-one mistakes in loops:
for (int i = 0; i <= numbers.length; i++) { // ⚠️ should be <
System.out.println(numbers[i]); // throws at i == length
}
This is one of the most common bugs in Java code. Use < length, not <= length. The enhanced for loop avoids this entirely:
for (int n : numbers) { // no manual bounds management
System.out.println(n);
}
Interactive animation: Looping with i <= numbers.length prints every element, then throws ArrayIndexOutOfBoundsException on the pass after the last.
Multiple Arrays of the Same Type
Java arrays are typed — an int[] can only hold ints. You can't put a String into an int array:
int[] numbers = new int[5];
numbers[0] = 42; // ok
numbers[1] = "hello"; // compile error — incompatible types
If you need a collection of mixed types, you'd use Object[] (the parent of all types) or a typed collection. Arrays don't have an "any type" mode without losing the type information.
For arrays of reference types, the array can hold any subtype:
Number[] nums = new Number[3];
nums[0] = 42; // Integer is a Number — ok
nums[1] = 3.14; // Double is a Number — ok
nums[2] = "hello"; // String is not a Number — compile error
Java arrays are covariant — Integer[] is treated as a subtype of Number[]. This is convenient but causes some bugs (we cover this more in Module 15 on generics).
Printing Arrays
A common surprise:
int[] numbers = {1, 2, 3};
System.out.println(numbers); // [I@1540e19d (or similar)
Calling println on an array prints the array's identity hash, not its contents. To print the contents, use Arrays.toString():
System.out.println(Arrays.toString(numbers)); // [1, 2, 3]
For multidimensional arrays, use Arrays.deepToString():
int[][] matrix = {{1, 2}, {3, 4}};
System.out.println(Arrays.deepToString(matrix)); // [[1, 2], [3, 4]]
This is one of the most common surprises for newcomers. Topic 4.4 covers the Arrays utility class in detail — toString is just one of many useful methods.
Interactive animation: println on an array prints its identity hash, while Arrays.toString and Arrays.deepToString print the contents.
Common Pitfalls
Warning: Confusing
length(array property) withlength()(String method). Arrays use.length(no parens). Strings use.length()(with parens). Lists use.size(). Mixing them up is a frequent compile error.Off-by-one in array iteration.
for (int i = 0; i <= arr.length; i++)accessesarr[arr.length]on the last iteration. Always use<, not<=.Reference equality on arrays.
array1 == array2andarray1.equals(array2)compare references. UseArrays.equals(array1, array2)for content equality.Forgetting null checks for reference arrays.
User[] users = new User[5]; users[0].getName();throws NPE becauseusers[0]is null. Reference arrays start with all nulls.Fixed size. Arrays cannot grow or shrink. If you need a dynamic collection, use
ArrayList(Module 14). Trying to add an 11th element to anew int[10]doesn't work — you'd have to create a new larger array and copy.
Why This Matters in Interviews
Interview: Array questions appear in nearly every coding interview. The basics — declaration, indexing, length, iteration — are screening filters. The deeper material (two pointers, sliding windows, sorting, searching) comes in problem-solving rounds.
Topic 4.6 covers the Interview Lens for arrays, including the highest-frequency interview patterns.
Try It
Exercise: Verify each behavior in your IDE:
- Declare
int[] awithout initializing. Try to accessa[0]— observe the NullPointerException.- Create
int[] a = new int[3]. Print each element — see they're all 0.- Create
String[] s = new String[3]. Trys[0].length()— observe the NPE because the element is null.- Create two arrays with identical contents. Compare with
==,.equals(), andArrays.equals(). Note the differences.- Try
int[] a = {1,2,3}; int[] b = a; b[0] = 99;. Printa[0]— see it changed.- Loop with
i <= arr.length— observe the ArrayIndexOutOfBoundsException.Each error teaches a specific rule. Experiencing them once makes them automatic to avoid later.