From a list to a table
A one-dimensional array holds a list of values. Many real data sets are tables: the seats in a cinema (rows and seat numbers), the pixels of an image (rows and columns), a game board, a week-by-week timetable. A two-dimensional (2D) array holds a table. Every element is found with two numbers: which row, then which column.
The key idea from Java’s point of view is that a 2D array is stored as an array of arrays. The outer array has one slot for each row. Each slot holds a reference to an ordinary one-dimensional array: the row itself. Because of this, almost everything you know about 1D arrays carries over: zero-based indexes, a fixed size set at creation, and the exception when an index is out of range.
For the exam, arr[first][second] means: first is the row index and second is the column index. The course covers rectangular arrays, in which every row has the same length; non-rectangular (“jagged”) arrays are outside the scope of the course and exam.
Picturing it
Figure 1 shows int[][] m = { {1, 2, 3}, {4, 5, 6} }; as a grid. Figure 2 shows how Java stores it.
Notice three facts that the pictures make clear.
- The grid has 2 rows and 3 columns.
m[1]is the second row, the array{4, 5, 6}.m[1][2]is the element at index 2 of that row array, which is 6.
Creating a 2D array
There are two ways.
With new and two sizes.
int[][] grid = new int[3][4]; // 3 rows, 4 columns
All 12 elements are created with the default value for the element type: 0 for int, 0.0 for double, false for boolean and null for any reference type such as String. Printing a new int[3][4] gives twelve 0s; a new boolean[2][3] gives false and a new double[2][2] gives 0.0.
With an initializer list. A list of lists, one inner list per row:
int[][] m = { {1, 2, 3}, {4, 5, 6} };
The size comes from the lists. Here that is 2 rows of 3.
The size of the array is fixed when it is created and cannot change. A 2D array can hold primitive values or object references.
Reading, writing and measuring
| Expression | Meaning | For m above |
|---|---|---|
m[r][c] |
element at row r, column c |
m[1][2] is 6 |
m[r][c] = v; |
change that element | |
m.length |
number of rows | 2 |
m[0].length |
number of columns (the length of a row) | 3 |
m[r] |
the whole row r, as a 1D array |
m[1] is {4, 5, 6} |
m[r].length |
length of row r |
3 |
The valid row indices run from 0 to m.length - 1. The valid column indices run from 0 to m[0].length - 1. Any other index throws an ArrayIndexOutOfBoundsException. In the runs m[2][0], m[0][3] and m[0][-1] each threw java.lang.ArrayIndexOutOfBoundsException.
An easy mistake is to swap the two sizes. If you remember “rows first”, then grid.length is the first number in new int[3][4], and grid[0].length is the second. For grid the program printed 3 4 4: three rows, and each of rows 0 and 2 has length 4.
Rows are references
Because m[1] is a reference to a 1D array, assigning it to another variable creates an alias, not a copy.
int[] row = m[1];
row[0] = 40;
// m[1][0] is now 40
Running this prints m as 1 2 3 | 40 5 6 |. The same fact lets you swap two rows by swapping their references:
int[] tmp = n[0];
n[0] = n[1];
n[1] = tmp;
On { {1, 2, 3}, {4, 5, 6} } this gave 4 5 6 | 1 2 3 |. Likewise, int[][] alias = nn; makes both variables refer to the same 2D array, so a change through one is seen through the other (changing alias[0][0] to 100 made nn[0][0] print 100).
Worked example 1: creating and filling a grid
Task. Trace the code and show grid at the end.
int[][] grid = new int[3][4];
grid[1][2] = 7;
grid[2][0] = grid[1][2] + 1;
Step 1. new int[3][4] creates 3 rows of 4 zeros.
| col 0 | col 1 | col 2 | col 3 | |
|---|---|---|---|---|
| row 0 | 0 | 0 | 0 | 0 |
| row 1 | 0 | 0 | 0 | 0 |
| row 2 | 0 | 0 | 0 | 0 |
Step 2. grid[1][2] = 7; sets row 1, column 2 to 7.
Step 3. grid[2][0] = grid[1][2] + 1; reads the 7, adds 1 and stores 8 in row 2, column 0.
| col 0 | col 1 | col 2 | col 3 | |
|---|---|---|---|---|
| row 0 | 0 | 0 | 0 | 0 |
| row 1 | 0 | 0 | 7 | 0 |
| row 2 | 8 | 0 | 0 | 0 |
Check. grid.length is 3, grid[0].length is 4. The run printed 3 4 4 and the grid 0 0 0 0 | 0 0 7 0 | 8 0 0 0 |, which matches the table.
Worked example 2: a seating chart of Strings
Task. A hall has 3 rows of 4 seats. Create the chart, seat “Ana” in row 0, seat 1 and “Raj” in row 2, seat 3, and report how many seats are taken out of how many.
String[][] seats = new String[3][4];
seats[0][1] = "Ana";
seats[2][3] = "Raj";
int taken = 0;
for (int r = 0; r < seats.length; r++)
{
for (int c = 0; c < seats[r].length; c++)
{
if (seats[r][c] != null)
{
taken++;
}
}
}
System.out.println(taken + " of " + seats.length * seats[0].length);
Reasoning.
- A
String[][]holds references, so every element starts asnull, meaning “no object”. An empty seat isnull, not"". - The nested loop visits every seat. The outer loop uses
seats.length(rows); the inner loop usesseats[r].length(columns of rowr). Topic 4.12 studies these loops in detail. - Only two seats are non-null, so
takenis 2. - The total is
seats.length * seats[0].length= 3 * 4 = 12.
The output was 2 of 12.
Why != null and not .equals. Calling a method on a null element throws a NullPointerException. Running names[0][0].length() on a new String[2][2] threw java.lang.NullPointerException. Test for null with == or != before calling methods on an element.
Common misconceptions
- “The first index is the column.” For the exam it is the row:
arr[row][col]. - “
arr.lengthis the total number of elements.” It is the number of rows only. The total isarr.length * arr[0].length. - “
arr[0].lengthis the number of rows.” It is the number of columns. - “A new
String[][]contains empty Strings.” It containsnull. - “
arr[r]copies the row.” It is a reference to the same row array. - “A 2D array can be resized.” The size is fixed when it is created.
- “A valid column index is
arr.length - 1.” That is the last valid row index, unless the table happens to be square.
Where this leads
Next, Topic 4.12 traverses 2D arrays with nested loops in row-major and column-major order; Topic 4.13 applies the standard algorithms (sum, maximum, count, shift) to rows, columns and whole tables; and 2D arrays also appear in the free-response section of the exam. Practise with the Topic 4.11 practice questions, recap with the revision notes and tick off the checklist. Next: the Topic 4.12 study guide on 2D array traversals.
Quick questions
Is the first index the row or the column?
For the exam the first index is the row and the second is the column: arr[row][col]. Picture rows going across the page and columns going down.
How do I find the number of rows and columns?
The number of rows is arr.length. The number of columns is arr[0].length, the length of any one row. Rows and columns are written the same way for every rectangular 2D array.
What are the default values of a new 2D array?
Every element gets the default for its type: 0 for int, 0.0 for double, false for boolean and null for reference types such as String.
Can the size of a 2D array change after it is created?
No. The numbers of rows and columns are fixed when the array is created. To get a different size you must create a new array.