array.length
[] subscript operator
▸ Memory layout
Arrays are objects.
If you can have an array of objects...
...and arrays are objects...
Can you have an array
of arrays?
An array of arrays is called a 2D Array
We know a regular array looks like this — a variable that references a block of data:
What if each element in that outer array held a reference to another array? Sketch what that structure would look like — then continue.
Then advance to the next slide ⟶
Imagine building a game that needs a map. The natural way to represent it is as a grid of cells.
To store the elevation of each cell, you'd want something like this grid →
Elevation Grid
To store grid data, make each row its own int[] array:
int[] r0 = {4, 6, 8, 10, 12};
int[] r1 = {6, 7, 11, 12, 16};
int[] r2 = {5, 6, 10, 14, 16};
int[] r3 = {4, 6, 10, 13, 15};
int[] r4 = {3, 5, 9, 12, 14};
Instead of 5 separate row variables, store them all in one outer array that holds references to each row:
→ An array of arrays = a 2D array, because it has both length and width.
1D Array (familiar)
// Declares an array with 3 cells int[] arr = new int[3];
2D Array (new!)
// 3 rows, 5 columns int[][] arr = new int[3][5];
The first index is the row, the second index is the column. Both are required to access a single element:
arr[1][3] = 99; // row 1, col 3 arr[0][0] = 42; // row 0, col 0 (top-left)
arr is an array of int arraysint[][] arr = new int[3][5];
arr.length == 3
The outer array holds 3 rows
arr[0].length == 5
Each row has 5 columns
Since a 2D array is an array of arrays, each row can have a different length.
Always use arr[row].length when iterating columns — it handles
ragged arrays safely:
Ragged Array
arr[0].length = 5 arr[1].length = 2
for (int row = 0; row < arr.length; row++) { for (int col = 0; col < arr[row].length; col++) { // Safe for ragged arrays! } }
* Ragged arrays won't appear on the AP exam — but good to know!
Java stores 2D arrays in row-major order: elements of each row are stored consecutively in memory.
A1 is stored next to A2 next to A3B1 may be adjacent to A3, but Java does not guarantee it — the next row could be elsewhere in memoryThis is why iterating row-by-row is more cache-friendly than column-by-column.
Logical grid
In memory
Declare and populate a 2D array in one statement using nested curly braces:
int[][] matrix = { {0, 1, 2, 3 }, // row 0 {10, 11, 12, 13}, // row 1 {20, 21, 22, 23} // row 2 };
Results in:
int[][] matrix = new int[3][4]; for (int row = 0; row < matrix.length; row++) { for (int col = 0; col < matrix[row].length; col++) { matrix[row][col] = row * 10 + col; } }
Formula: row * 10 + col
0×10+0=0, 0×10+1=1 …1×10+0=10, 1×10+1=11 …Results in:
int[][] matrix = new int[3][4]; for (int[] row : matrix) { for (int col = 0; col < row.length; col++) { row[col] = 10 * col; } }
✓ Yes, it works!
for gives you each int[] row as a referencerow do affect the original matrixResult:
int[][] matrix = new int[3][4]; for (int[] row : matrix) { for (int val : row) { val = 10; } }
✗ No — it doesn't work!
int val is a copy of the value stored in the array cellval = 10 updates only the local copy — matrix is never touchedint[] rows because arrays are references; primitive ints are notResult — matrix is unchanged (all zeros):
int[][] matrix = new int[3][3]; for (int r = 0, c = 0; r < matrix.length; r++, c++) { matrix[r][c] = 99; }
✗ Not quite!
r and c step together: (0,0) → (1,1) → (2,2)r = k / cols and c = k % cols from a single counterTwo variables, one loop
for allows multiple declarations in the init clause, separated by a comma:int r = 0, c = 0r++, c++. Both step on every iteration.Result — only the diagonal is set
(6 cells remain 0):