01 · Java basics — note 9 of 12
Arrays
Store sequences in contiguous memory, access elements by index, and process collections efficiently.
An array is a fixed-size contiguous sequence of elements of the same type, accessed in a single step through zero-based indexes.
The idea in real life
Think of a row of numbered lockers at a train station. Every locker has the exact same dimensions, sits directly next to its neighbour, and is identified by a clear number starting from 0. If you know locker 0 is at the entrance, you can walk directly to locker 4 without opening or inspecting the lockers in between. Arrays work the same way in Java: they store a fixed number of items of the same type side by side in memory, letting you jump directly to any position using its index.
Why it exists
- Storing dozens or hundreds of related values in separate variable names (such as
score1,score2, andscore3) makes code verbose, repetitive, and impossible to scale dynamically. - Independent variables cannot be traversed systematically inside a loop, requiring manual duplication of code for every calculation.
- Grouping elements into a single contiguous structure lets your program index, sort, filter, and pass large datasets across methods with a single reference variable.
- Knowing that elements sit side by side in memory allows the computer to calculate memory locations immediately, retrieving any element without scanning prior entries.
How it works
Declaring and creating arrays
Allocate a fixed contiguous sequence of default-initialised elements in memory.
An array is a data structure that stores a fixed number of values of a single type in contiguous memory slots.
To use an array in Java, you perform two distinct steps: declaration and creation.
- Declaration: You declare an array variable by specifying the element type followed by square brackets
[]and the variable identifier, such asint[] scores;. While Java also allows C-style declarations likeint scores[];, the conventionint[] scores;is preferred because it places the complete type on the left. - Creation: You create an array object on the heap using the
newkeyword, followed by the element type and the desired size in brackets:scores = new int[5];. You can combine declaration and creation on a single line:int[] scores = new int[5];.
When an array is created with new, the JVM automatically initializes every slot to the default value for its type, as taught in variables and primitive types:
- Numeric primitive types (
byte,short,int,long) default to0or0L. - Floating-point types (
float,double) default to0.0for0.0. - Boolean types (
boolean) default tofalse. - Character types (
char) default to'\u0000'(the null character). - Reference types default to
null.
If you already know the elements when declaring the array, you can use an array literal enclosed in curly braces { ... }. Java creates the array object on the heap, sizes it to match the number of values provided, and populates the elements in order.
public class Main {
public static void main(String[] args) {
// Allocate an array of 4 integers with default values.
int[] scores = new int[4];
// Allocate and initialise using an array literal.
int[] primes = { 2, 3, 5, 7 };
// Default values for primitive types.
boolean[] flags = new boolean[2];
double[] measurements = new double[2];
System.out.println("Default int: " + scores[0]);
System.out.println("Literal prime: " + primes[2]);
System.out.println("Default boolean: " + flags[0]);
System.out.println("Default double: " + measurements[0]);
}
}Default int: 0
Literal prime: 5
Default boolean: false
Default double: 0.0In this program:
scoresis an array of 4 integers; every slot begins with the default value 0.primesis initialized using an array literal with 4 explicit prime values.flagsis an array of 2 booleans, both initialized tofalse.measurementsis an array of 2 doubles, both initialized to0.0.
Indexing and length
Access elements with zero-based indexes up to length minus one.
Every element in an array is accessed by its position, known as its index.
Java arrays use zero-based indexing:
- The first element sits at index
0. - The second element sits at index
1. - The final element sits at index
length - 1.
To read a value from an array, write the array variable name followed by the index enclosed in square brackets: scores[0]. To assign a new value to a slot, place the indexed expression on the left side of an assignment operator: scores[0] = 85;.
Every array object has a public final field named length that stores the total number of elements the array can hold. Because length is a field rather than a method, you access it without parentheses: scores.length.
public class Main {
public static void main(String[] args) {
int[] scores = new int[3];
scores[0] = 85;
scores[1] = 92;
scores[2] = 78;
int firstScore = scores[0];
int lastScore = scores[scores.length - 1];
System.out.println("Array length: " + scores.length);
System.out.println("First element: " + firstScore);
System.out.println("Last element: " + lastScore);
}
}Array length: 3
First element: 85
Last element: 78In this program:
scoresis allocated with length 3.- Values 85, 92, and 78 are assigned to indices 0, 1, and 2.
scores.lengthevaluates to 3.scores[scores.length - 1]accesses index 2, which holds the final element 78.
If you attempt to access an index that is less than 0 or greater than or equal to length, Java prevents invalid memory access by immediately throwing an ArrayIndexOutOfBoundsException at runtime:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
at Main.main(Main.java:4)The error message explicitly names the invalid index requested (3) and the valid array length (3), helping you pinpoint the off-by-one error in your indexing logic.
Looping over an array
Visit every slot with an indexed loop or clean for-each syntax.
As introduced in loops, repeating operations over sequences is a core programming task. Java provides two primary loop patterns for traversing arrays: indexed for loops and enhanced for-each loops.
An indexed for loop uses a counter i starting at 0 and continuing while i < array.length:
- It provides direct access to the current index
i. - It allows you to modify array elements in place (
numbers[i] *= 2). - It enables traversing backwards, skipping elements, or comparing adjacent pairs (
numbers[i]andnumbers[i + 1]).
An enhanced for-each loop extracts each element sequentially:
- It eliminates the need for an index variable and removes boundary conditions, preventing off-by-one errors.
- It provides read-only access to values; assigning to the loop variable (
val = 10;) modifies only that local copy, leaving the original array slot untouched.
public class Main {
public static void main(String[] args) {
int[] values = { 10, 20, 30, 40 };
// Indexed loop: access elements and indices.
for (int i = 0; i < values.length; i++) {
System.out.println("Index " + i + ": " + values[i]);
}
// For-each loop: read each value directly.
int total = 0;
for (int val : values) {
total += val;
}
System.out.println("Total sum: " + total);
}
}Index 0: 10
Index 1: 20
Index 2: 30
Index 3: 40
Total sum: 100In this program:
- The indexed
forloop prints each index from 0 to 3 alongside its corresponding value. - The enhanced
for-eachloop visits each element invalues, accumulating the numbers intototalto produce 100.
Arrays are objects
Array variables hold references that share heap memory on assignment.
In Java, arrays are reference types, not primitive types. An array variable does not store the array elements directly; it stores a reference to an array object on the heap.
When you assign one array variable to another, Java copies the reference, not the underlying array data. Both variables now refer to the same array object. Any modification made through one variable immediately affects what is visible through the other. To make an independent duplicate instead, create a genuine copy (see copying arrays).
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] a = {1, 2, 3};
int[] b = a;
b[0] = 99;
System.out.println(a[0]);
System.out.println(b[0]);
}
}99
99Step through the program below to watch both variables point to the same array on the heap. Switch b is to a copy to see how a genuine copy creates a separate array.
As covered in methods, Java passes all method arguments by value. When you pass an array to a method, Java copies the reference into the method parameter. Because both references point to the same heap object, modifying elements inside the method directly updates the caller's array. However, reassigning the parameter variable itself inside the method simply points the local parameter to a different object, leaving the caller's reference unchanged.
Going deeper
Copying arrays
Duplicate elements into independent arrays to prevent unintended shared mutations.
When you want to modify an array without altering the original dataset, you must create a genuine copy rather than assigning references. Java provides four standard ways to duplicate array data:
Arrays.copyOf(original, newLength): Allocates a new array with the specified length and copies elements from the beginning oforiginal. IfnewLengthis greater thanoriginal.length, additional slots are initialized to default values. IfnewLengthis smaller, the result is truncated.Arrays.copyOfRange(original, fromIndex, toIndex): Allocates a new array containing elements fromfromIndex(inclusive) totoIndex(exclusive). The length of the new array istoIndex - fromIndex.System.arraycopy(source, srcPos, destination, destPos, length): A low-level native method that copieslengthelements fromsourcestarting atsrcPosinto an already allocateddestinationarray starting atdestPos. It is implemented directly in native C++ inside the JVM and performs fast bulk memory copies.original.clone(): Returns a new array containing a shallow copy of all elements inoriginal.
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] source = { 10, 20, 30, 40, 50 };
// Arrays.copyOf creates an independent array of specified length.
int[] fullCopy = Arrays.copyOf(source, source.length);
// Arrays.copyOfRange copies a slice [fromIndex, toIndex).
int[] middleSlice = Arrays.copyOfRange(source, 1, 4);
// System.arraycopy transfers elements into an existing array.
int[] target = new int[3];
System.arraycopy(source, 2, target, 0, 3);
// Mutating source does not affect genuine copies.
source[2] = 999;
System.out.println("source[2]: " + source[2]);
System.out.println("fullCopy[2]: " + fullCopy[2]);
System.out.println("middleSlice length: " + middleSlice.length);
System.out.println("target[0]: " + target[0]);
}
}source[2]: 999
fullCopy[2]: 30
middleSlice length: 3
target[0]: 30In this program:
fullCopyis an independent duplicate created byArrays.copyOf. Modifyingsource[2]to 999 leavesfullCopy[2]untouched at 30.middleSliceextracts indices 1, 2, and 3 ({ 20, 30, 40 }), producing an array of length 3.System.arraycopytransfers 3 elements starting fromsource[2]directly intotarget[0], fillingtargetwith{ 30, 40, 50 }.
Two-dimensional arrays
Build grids as arrays of arrays with independent row lengths.
In Java, multidimensional arrays are implemented as arrays of arrays. A two-dimensional array is an array object whose individual elements are themselves references to one-dimensional array objects.
To allocate a rectangular grid of 2 rows and 3 columns, write int[][] grid = new int[2][3];:
grid.lengthgives the number of rows (2).grid[r].lengthgives the number of columns in rowr(3).grid[r][c]accesses the element at row indexrand column indexc.
Because Java represents multidimensional arrays as arrays of array references, rows do not have to be the same size. An array where different rows have different lengths is called a jagged array (or ragged array).
To create a jagged array, declare the outer array with its row count while omitting the inner dimension: int[][] triangle = new int[3][];. You then allocate each individual row array independently with its own length.
public class Main {
public static void main(String[] args) {
// Standard rectangular matrix: 2 rows, 3 columns.
int[][] matrix = {
{ 1, 2, 3 },
{ 4, 5, 6 }
};
System.out.println("Matrix row count: " + matrix.length);
System.out.println("Matrix column count: " + matrix[0].length);
// Jagged array: each row has an independent length.
int[][] jagged = new int[3][];
jagged[0] = new int[] { 1 };
jagged[1] = new int[] { 2, 3 };
jagged[2] = new int[] { 4, 5, 6 };
// Row-by-row traversal with nested loops.
for (int r = 0; r < jagged.length; r++) {
for (int c = 0; c < jagged[r].length; c++) {
System.out.print(jagged[r][c] + " ");
}
System.out.println();
}
}
}Matrix row count: 2
Matrix column count: 3
1
2 3
4 5 6 In this program:
matrixis a rectangular array with 2 rows and 3 columns.jaggedis allocated with 3 rows, where row 0 has length 1, row 1 has length 2, and row 2 has length 3.- Nested loops iterate through the jagged structure row by row, using
jagged[r].lengthas the inner loop limit.
The Arrays class
Use static helper methods for printing, filling, searching, and sorting.
The standard library class java.util.Arrays provides static helper methods for performing common operations on arrays:
Arrays.toString(array): Converts a one-dimensional array into a readable formatted string such as[10, 20, 30]. Passing an array directly toSystem.out.printlnprints an object identifier like[I@15db9742;Arrays.toStringprints the actual elements.Arrays.deepToString(grid): Recursively converts multidimensional arrays into human-readable strings, formatting all nested levels.Arrays.fill(array, value): Assigns the specified value to every element of the array. You can also specify range boundaries:Arrays.fill(array, fromIndex, toIndex, value).Arrays.sort(array): Sorts elements into ascending numerical order in place. For primitive arrays, Java uses a Dual-Pivot Quicksort algorithm. Sorting algorithms will be studied in depth in chapter 16.Arrays.equals(array1, array2): Returnstrueif both arrays contain the same number of elements and corresponding pairs of elements are equal. The==operator checks only whether both variables point to the same array object, whereasArrays.equalscompares the contents.Arrays.deepEquals(grid1, grid2): Compares multidimensional arrays for element-by-element equality across all nested dimensions.Arrays.binarySearch(sortedArray, key): Searches a sorted array for a target key, returning its index if found, or a negative insertion point if absent. Searching algorithms are explored in chapter 18.
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] numbers = { 50, 20, 40, 10, 30 };
// Format 1D array as a readable string.
System.out.println("Before sort: " + Arrays.toString(numbers));
// Sort primitive array in ascending numerical order in place.
Arrays.sort(numbers);
System.out.println("After sort: " + Arrays.toString(numbers));
// Compare content equality between two arrays.
int[] expected = { 10, 20, 30, 40, 50 };
boolean areEqual = Arrays.equals(numbers, expected);
System.out.println("Equals expected: " + areEqual);
// Fill an array with a specific value.
int[] board = new int[4];
Arrays.fill(board, -1);
System.out.println("Filled board: " + Arrays.toString(board));
// Format multidimensional arrays.
int[][] grid = { { 1, 2 }, { 3, 4 } };
System.out.println("Grid: " + Arrays.deepToString(grid));
}
}Before sort: [50, 20, 40, 10, 30]
After sort: [10, 20, 30, 40, 50]
Equals expected: true
Filled board: [-1, -1, -1, -1]
Grid: [[1, 2], [3, 4]]In this program:
Arrays.toStringformatsnumbersbefore and after sorting.Arrays.sortrearrangesnumbersin ascending order in place.Arrays.equalsverifies thatnumbersmatchesexpectedelement by element.Arrays.fillpopulates every slot ofboardwith-1.Arrays.deepToStringformats the 2Dgridarray.
Prefix sums
Precompute running totals to calculate range sums with one subtraction.
A frequent challenge in algorithm problems is finding the sum of elements within a slice of an array repeatedly. Summing elements from index left to index right with a loop requires stepping through all elements in that range each time a question is asked. If you answer thousands of queries on a large array, repeating that loop becomes slow.
The prefix sum pattern solves this by precomputing cumulative totals in a single pass:
- Allocate an auxiliary array
prefixof sizenums.length + 1. - Set
prefix[0] = 0. - For each index
ifrom 0 tonums.length - 1, computeprefix[i + 1] = prefix[i] + nums[i].
Each slot prefix[k] stores the sum of the first k elements of nums (from index 0 up to k - 1).
Once the prefix array is built, the sum of any subarray from index left to index right (inclusive) is calculated in a single arithmetic operation:
rangeSum = prefix[right + 1] - prefix[left];
Because prefix[right + 1] holds the total of elements from index 0 to right, subtracting prefix[left] removes the sum of all elements prior to left, leaving exactly the desired range sum.
When summing many integers, the cumulative total can easily exceed Integer.MAX_VALUE (2,147,483,647), causing integer overflow. To keep calculations exact, declare the prefix array using the 64-bit long type, as covered in variables and primitive types.
public class Main {
public static void main(String[] args) {
int[] nums = { 3, 1, 4, 1, 5, 9 };
// Build prefix sum array of size n + 1 with 64-bit long.
long[] prefix = new long[nums.length + 1];
for (int i = 0; i < nums.length; i++) {
prefix[i + 1] = prefix[i] + nums[i];
}
// Query sum of range [left, right] inclusive in one subtraction.
int left = 1;
int right = 4;
long rangeSum = prefix[right + 1] - prefix[left];
System.out.println("Prefix array: ");
for (int i = 0; i < prefix.length; i++) {
System.out.print(prefix[i] + " ");
}
System.out.println();
System.out.println("Sum of range [1, 4]: " + rangeSum);
}
}Prefix array:
0 3 4 8 9 14 23
Sum of range [1, 4]: 11In this program:
numscontains 6 integers.prefixis created with length 7.prefix[0]is 0, and each subsequent slot accumulatesnums[i].- For
left = 1andright = 4, the range spans elementsnums[1]throughnums[4](1 + 4 + 1 + 5 = 11). prefix[5] - prefix[1]calculates14 - 3 = 11with a single subtraction.
Under the hood
Memory layout
Elements sit consecutively in memory directly behind the object header.
In Java, every array is an object allocated dynamically on the heap. Its physical structure in memory consists of two distinct regions:
- Object Header: A small metadata header maintained by the JVM. It stores internal runtime flags (such as garbage collection state and lock status), a reference to the array's class metadata, and the 32-bit
lengthfield. The exact size of this header depends on the JVM architecture and whether compressed reference pointers are enabled. - Element Payload: The contiguous memory block holding the array elements, positioned immediately after the header.
For primitive arrays (such as int[] or double[]), the actual primitive values sit directly inside the payload in consecutive byte addresses. In an int[], each 32-bit integer occupies 4 contiguous bytes: element 0 sits at offset 0 of the payload, element 1 sits at offset 4, element 2 sits at offset 8, and so on.
For reference arrays (such as int[][]), the payload does not store nested data directly. Instead, each slot in the outer array holds an address reference pointing to an independent array object allocated elsewhere on the heap. Because each row is a separate object, row arrays are not guaranteed to sit consecutively in memory.
Why indexing is fast
Find any element's position with one small calculation.
Because primitive array elements sit consecutively in memory and every element of a given type occupies an identical number of bytes, the JVM does not need to walk through elements to locate a specific index.
Instead, the position of element i comes from one calculation:
position = start + (i * element_size)
Here:
startis where the array's elements begin in memory.element_sizeis the fixed byte size of the element type (such as 4 bytes forintor 8 bytes forlong).iis the requested index.
Modern CPU architectures support this calculation directly in hardware through indexed addressing modes (such as base-plus-scaled-index instructions). As a result, reading scores[0] and reading scores[500000] execute in the exact same number of machine cycles. Access time does not depend on the total length of the array or the magnitude of the index. In chapter 06, you will learn how Big-O notation formalises this property as constant-time performance.
Bounds checks
The JVM verifies bounds in bytecode to ensure memory safety.
In low-level languages like C, accessing an out-of-bounds index reads or overwrites whatever data happens to sit at that calculated position, creating severe memory corruption and security vulnerabilities. Java eliminates this risk by mandating bounds checks at the virtual machine level.
Every array access in compiled Java bytecode is performed by dedicated instructions:
ialoadreads an integer from an array reference and index on the operand stack.iastorewrites an integer into an array slot from the operand stack.arraylengthextracts the length from the array object header.
Under §6.5 of the Java Virtual Machine Specification, whenever iaload or iastore executes, the JVM automatically checks two conditions:
- The array reference must not be
null(otherwise it throwsNullPointerException). - The index must satisfy
0 <= index < arraylength(otherwise it throwsArrayIndexOutOfBoundsException).
Inspecting bytecode with javap -c reveals these exact instructions:
Compiled from "ArrayOperations.java"
public class ArrayOperations {
static int getElement(int[], int);
Code:
0: aload_0
1: iload_1
2: iaload
3: ireturn
static void setElement(int[], int, int);
Code:
0: aload_0
1: iload_1
2: iload_2
3: iastore
4: return
static int getLength(int[]);
Code:
0: aload_0
1: arraylength
2: ireturn
}In this compiled bytecode:
- In
getElement,aload_0pushes the array reference andiload_1pushes the index onto the operand stack.ialoadverifies the bounds and pushes the retrieved integer. - In
setElement,aload_0,iload_1, andiload_2push the array reference, index, and value.iastoreverifies the bounds and stores the value. - In
getLength,arraylengthreads the length field directly from the array header.
Although the specification requires bounds checks on every access, modern Just-In-Time (JIT) compilers optimize hot loops. When the JIT compiler analyzes a loop header like for (int i = 0; i < nums.length; i++), it can mathematically prove that i never falls below 0 and never reaches nums.length. In such cases, the JIT compiler safely hoists or eliminates the individual boundary checks from the compiled machine code, providing full memory safety with maximum execution speed.
Fixed size
Array capacity is permanent once allocated on the heap.
When an array is allocated with new, the JVM reserves a contiguous chunk of memory on the heap sized precisely for the requested number of elements. Once this block is allocated, its size cannot grow or shrink.
An array's size is fixed because contiguous memory directly adjacent to the array may already be occupied by other objects on the heap. Expanding the array in place would overwrite adjacent heap data.
If your application needs to store more elements than the allocated array can hold, you must allocate a new, larger array and copy the existing elements over using Arrays.copyOf or System.arraycopy. In chapter 04, you will learn how the ArrayList class automates this resizing process.
In Java
Here is a complete program that brings these concepts together: inspecting bounds, accumulating prefix sums with long arithmetic, copying arrays safely, sorting and searching elements, and traversing a multidimensional grid.
In this program:
findMinlocates the smallest integer in an array.buildPrefixSumsconstructs a cumulative prefix sum array using 64-bitlongstorage.queryRangeSumcalculates the sum of elements betweenleftandrightinclusive using a single subtraction.sumGridcomputes the total sum of all values in a two-dimensional grid.
import java.util.Arrays;
public class Main {
// Returns the smallest integer found in the provided array.
static int findMin(int[] numbers) {
int lowest = numbers[0];
for (int i = 1; i < numbers.length; i++) {
if (numbers[i] < lowest) {
lowest = numbers[i];
}
}
return lowest;
}
// Returns a prefix sum array computed with 64-bit long accumulation.
static long[] buildPrefixSums(int[] numbers) {
long[] prefix = new long[numbers.length + 1];
for (int i = 0; i < numbers.length; i++) {
prefix[i + 1] = prefix[i] + numbers[i];
}
return prefix;
}
// Returns the sum of elements between left and right inclusive.
static long queryRangeSum(long[] prefix, int left, int right) {
return prefix[right + 1] - prefix[left];
}
// Calculates and returns the sum of all elements in a 2D grid.
static long sumGrid(int[][] grid) {
long total = 0;
for (int r = 0; r < grid.length; r++) {
for (int c = 0; c < grid[r].length; c++) {
total += grid[r][c];
}
}
return total;
}
public static void main(String[] args) {
int[] scores = { 45, 12, 89, 33, 71 };
// Inspect boundaries and values.
int minScore = findMin(scores);
System.out.println("Original scores: " + Arrays.toString(scores));
System.out.println("Minimum score: " + minScore);
// Calculate prefix sums and answer range queries.
long[] prefix = buildPrefixSums(scores);
long rangeTotal = queryRangeSum(prefix, 1, 3);
System.out.println("Sum of range [1, 3]: " + rangeTotal);
// Create an independent copy and sort it.
int[] sortedScores = Arrays.copyOf(scores, scores.length);
Arrays.sort(sortedScores);
System.out.println("Sorted copy: " + Arrays.toString(sortedScores));
System.out.println("Original unchanged: " + Arrays.toString(scores));
// Binary search on sorted array.
int targetIndex = Arrays.binarySearch(sortedScores, 45);
System.out.println("Index of 45 in sorted: " + targetIndex);
// Process a 2D grid.
int[][] grid = {
{ 10, 20 },
{ 30, 40, 50 }
};
System.out.println("Grid: " + Arrays.deepToString(grid));
System.out.println("Grid total sum: " + sumGrid(grid));
}
}Original scores: [45, 12, 89, 33, 71]
Minimum score: 12
Sum of range [1, 3]: 134
Sorted copy: [12, 33, 45, 71, 89]
Original unchanged: [45, 12, 89, 33, 71]
Index of 45 in sorted: 2
Grid: [[10, 20], [30, 40, 50]]
Grid total sum: 150Traps
Using length instead of length - 1 as the last index
Because Java arrays use zero-based indexing, valid element positions range from
0tonums.length - 1. Attempting to read or write atnums.lengthexceeds the allocated boundary and causes the JVM to throwArrayIndexOutOfBoundsExceptionat runtime.✕ WRONGint last = nums[nums.length];✓ RIGHTint last = nums[nums.length - 1];Comparing array contents with == instead of Arrays.equals
The
==operator on arrays checks whether both variables point to the same array object. Even if two separate arrays have identical lengths and element values,firstArray == secondArrayevaluates tofalse. UseArrays.equalsto verify that corresponding elements match.✕ WRONGif (firstArray == secondArray) { ... }✓ RIGHTif (Arrays.equals(firstArray, secondArray)) { ... }Printing an array directly with println
Passing an array reference directly to
System.out.printlninvokesObject.toString(), which prints the internal type descriptor and hexadecimal identity hash code (such as[I@15db9742) rather than the array contents. UseArrays.toString(scores)for one-dimensional arrays orArrays.deepToString(grid)for nested arrays.✕ WRONGSystem.out.println(scores);✓ RIGHTSystem.out.println(Arrays.toString(scores));Assigning an array variable instead of copying elements
Assigning one array variable to another copies only the reference value, not the array data on the heap. Both variables point to the exact same memory slots, meaning modifications made through
backupimmediately changeoriginal. UseArrays.copyOforclone()when you need an independent duplicate.✕ WRONGint[] backup = original;✓ RIGHTint[] backup = Arrays.copyOf(original, original.length);Accessing unallocated rows in a jagged array
When creating a multidimensional array with unspecified inner dimensions, Java initializes each row reference to
null. Attempting to read or assign an element in an unallocated row attempts to dereference a null reference, throwing aNullPointerException. Allocate each inner row array before accessing its elements.✕ WRONGint[][] grid = new int[3][]; grid[0][0] = 5;✓ RIGHTint[][] grid = new int[3][]; grid[0] = new int[2]; grid[0][0] = 5;Sharing a single row array across multiple rows with Arrays.fill
Passing a single row array reference to
Arrays.fillstores the exact same reference into every slot ofgrid. Modifyinggrid[0][0]mutatesgrid[1][0]andgrid[2][0]because all rows share the same underlying array object. Instantiate a new array for each row inside a loop instead.✕ WRONGint[] row = new int[3]; Arrays.fill(grid, row);✓ RIGHTfor (int i = 0; i < grid.length; i++) { grid[i] = new int[3]; }Allowing prefix sums to overflow a 32-bit integer
Accumulating multiple values inside a prefix sum array can easily exceed
Integer.MAX_VALUE(2,147,483,647), causing silent two's complement integer overflow as taught in variables and primitive types. Declare the prefix accumulator array with typelong[]to prevent incorrect negative sums.✕ WRONGint[] prefix = new int[nums.length + 1];✓ RIGHTlong[] prefix = new long[nums.length + 1];Calling length as a method on arrays
The size of an array is exposed as a
public finalfield namedlength, not a method. Appending parentheses()is invalid syntax on arrays and causes a compile-time error:cannot find symbol method length(). Strings uselength(), while arrays uselength.✕ WRONGfor (int i = 0; i < nums.length(); i++)✓ RIGHTfor (int i = 0; i < nums.length; i++)