AI InterviewSearch…Search problems, topics, or pages…Ctrl KGet started
Skip to content

06 Arrays / Lesson 2 of 5

Two-dimensional and jagged arrays

12 min · +10 XP · 2 exercises · 5 questions

Read the text12 min
Exercises0/2
Quiz5 q

Quick answer

How do 2D arrays work in Java?

A 2D array in Java, such as int[][], is an array of arrays: an outer array whose elements are references to separate row arrays. new int[3][4] creates three rows of four zeros; grid.length is the number of rows and grid[r].length the length of row r. Because rows are independent objects, they can differ in length, which makes a jagged array.

Java has no true multi-dimensional arrays. int[][] is an array of arrays: an outer array whose elements are references to inner arrays, each of which can be any length — or null. That model explains everything about how grids are created, iterated, copied and sized, and it is what makes "jagged" arrays possible.

Creating a grid

int[][] grid = new int[3][4];       // 3 rows, each a new int[4] of zeros
grid[1][2] = 7;                     // row 1, column 2
grid.length                         // 3 — the number of rows
grid[0].length                      // 4 — the length of row 0
int[][] literal = {
    {1, 2, 3},
    {4, 5, 6},
};                                  // 2 × 3, trailing comma allowed

new int[3][4] allocates four objects: the outer int[3] and three int[4]s. Row-major is the convention — grid[row][col] — but nothing enforces it; it is simply the order of the indices.

Iterating

for (int r = 0; r < grid.length; r++) {
    for (int c = 0; c < grid[r].length; c++) {     // grid[r].length, not grid[0].length, if rows may differ
        System.out.print(grid[r][c] + " ");
    }
    System.out.println();
}

for (int[] row : grid) {          // for-each over rows
    for (int v : row) { … }
}

Iterating row by row (outer loop over rows) walks memory in the order it is laid out and is cache-friendly; column-first loops over a large grid are measurably slower.

Jagged arrays

Because rows are independent arrays, they need not be the same length:

int[][] triangle = new int[4][];        // 4 rows, all NULL
for (int r = 0; r < 4; r++) {
    triangle[r] = new int[r + 1];        // row r has r + 1 slots
}
// triangle[3].length == 4, triangle[0].length == 1

int[][] ragged = {{1}, {2, 3}, {}, {4, 5, 6}};   // literal jagged array; row 2 is empty

new int[4][] with the second dimension omitted creates only the outer array; each row is null until assigned. Pascal's triangle, adjacency lists, and "rows read from input of varying width" are natural jagged arrays.

Consequences: grid[0].length is not "the width" unless you know the grid is rectangular; a row may be null (NPE on grid[r].length); and grid[r] = grid[0] makes two rows the same array.

Rows are references

int[][] a = new int[2][2];
int[] row = a[0];
row[1] = 9;                       // a[0][1] is now 9 — row IS a[0]

int[][] b = a.clone();            // shallow: b is a new outer array, but b[0] == a[0]
b[0][0] = 5;                      // a[0][0] is also 5

clone(), Arrays.copyOf and System.arraycopy on the outer array copy the row references, not the rows. A deep copy is a loop: for (r …) b[r] = a[r].clone(); (or Arrays.stream(a).map(int[]::clone).toArray(int[][]::new)).

The same applies to printing and comparing: Arrays.toString(grid) prints [[I@…, [I@…]; use Arrays.deepToString(grid). Arrays.equals(a, b) compares row references; Arrays.deepEquals(a, b) compares contents.

Three and more dimensions

int[][][] cube = new int[2][3][4]; — an array of 2 arrays of 3 arrays of 4 ints. Same rules, one more level. Beyond three dimensions, consider a flat array with computed indices.

Flat arrays as grids

For performance-critical grids (image processing, dynamic programming tables), a single int[rows * cols] indexed as a[r * cols + c] avoids the per-row indirection and the extra objects, and keeps everything in one contiguous block. It is less readable; use it when measurement says so.

Reading a grid from input

int rows = in.nextInt(), cols = in.nextInt();
int[][] g = new int[rows][cols];
for (int r = 0; r < rows; r++)
    for (int c = 0; c < cols; c++)
        g[r][c] = in.nextInt();

For a character grid (mazes, boards): char[][] board = new char[rows][]; for (r …) board[r] = in.next().toCharArray(); — each line becomes a row.

Common patterns

  • Transpose (rectangular): t[c][r] = g[r][c] with t = new int[cols][rows].
  • Neighbours: check bounds 0 <= nr && nr < rows && 0 <= nc && nc < cols before g[nr][nc]; direction arrays int[] dr = {-1, 1, 0, 0}, dc = {0, 0, -1, 1} avoid four copies of the check.
  • Row sums / column sums: two nested loops; column sums accumulate into colSum[c] while walking rows.
  • Diagonals: main diagonal g[i][i]; anti-diagonal g[i][n - 1 - i].

Interview angle

  • "Is int[][] a matrix?" An array of arrays; rows are separate objects and may differ in length.
  • "How many objects does new int[3][4] create?" Four.
  • "Why does clone() on a 2D array not copy the contents?" It copies the outer array's references to the same rows.
  • "How do you print a 2D array?" Arrays.deepToString.

Key takeaways

  • int[][] is an array of row arrays; grid.length is rows, grid[r].length is that row's length.
  • new int[n][] leaves rows null; rows may be jagged and may be shared.
  • Copying, comparing and printing the outer array is shallow — use deepToString, deepEquals, and clone each row.
  • Iterate row-major; bounds-check neighbours with direction arrays.

Common questions

What is a jagged array in Java?

A jagged array is a 2D array whose rows have different lengths. new int[4][] creates only the outer array with every row null, and each row is then assigned on its own, for example triangle[r] = new int[r + 1] for Pascal's triangle.

How do you print a 2D array in Java?

Use Arrays.deepToString(grid). Arrays.toString(grid) prints only each row's type code and hash, such as [I@1b6d3586, because the outer array's elements are arrays; deepToString descends into every row and prints its values.

How do you deep copy a 2D array in Java?

Clone each row: create a new outer array and assign copy[r] = grid[r].clone() in a loop. grid.clone(), Arrays.copyOf and System.arraycopy on the outer array copy only the row references, so the copy and the original would share their rows.

How many objects does new int[3][4] create in Java?

Four: the outer int[3] array and three int[4] row arrays. Each row is a separate object on the heap, which is why rows can be shared, replaced or left null.

How do you get the number of rows and columns of a 2D array in Java?

grid.length is the number of rows and grid[r].length is the length of row r. grid[0].length is the column count only when the array is rectangular; in a jagged array each row must be measured separately.

Mark as readSign in to keep your place.

2D Arrays in Java: Jagged Arrays and Arrays of Arrays

A Java 2D array is an array of arrays, so rows can differ in length. Creating grids and jagged arrays, iterating, deep copying and printing with deepToString.

  • Course: Java study plan
  • Module: Arrays
  • Kind: Lesson
  • Reading time: 12 min
  • Runtime: OpenJDK 18

How do 2D arrays work in Java?

A 2D array in Java, such as int[][], is an array of arrays: an outer array whose elements are references to separate row arrays. new int[3][4] creates three rows of four zeros; grid.length is the number of rows and grid[r].length the length of row r. Because rows are independent objects, they can differ in length, which makes a jagged array.

Lesson

Java has no true multi-dimensional arrays. int[][] is an array of arrays: an outer array whose elements are references to inner arrays, each of which can be any length — or null. That model explains everything about how grids are created, iterated, copied and sized, and it is what makes "jagged" arrays possible.

Creating a grid

int[][] grid = new int[3][4];       // 3 rows, each a new int[4] of zeros
grid[1][2] = 7;                     // row 1, column 2
grid.length                         // 3 — the number of rows
grid[0].length                      // 4 — the length of row 0
int[][] literal = {
    {1, 2, 3},
    {4, 5, 6},
};                                  // 2 × 3, trailing comma allowed

new int[3][4] allocates four objects: the outer int[3] and three int[4]s. Row-major is the convention — grid[row][col] — but nothing enforces it; it is simply the order of the indices.

Iterating

for (int r = 0; r < grid.length; r++) {
    for (int c = 0; c < grid[r].length; c++) {     // grid[r].length, not grid[0].length, if rows may differ
        System.out.print(grid[r][c] + " ");
    }
    System.out.println();
}

for (int[] row : grid) {          // for-each over rows
    for (int v : row) { … }
}

Iterating row by row (outer loop over rows) walks memory in the order it is laid out and is cache-friendly; column-first loops over a large grid are measurably slower.

Jagged arrays

Because rows are independent arrays, they need not be the same length:

int[][] triangle = new int[4][];        // 4 rows, all NULL
for (int r = 0; r < 4; r++) {
    triangle[r] = new int[r + 1];        // row r has r + 1 slots
}
// triangle[3].length == 4, triangle[0].length == 1

int[][] ragged = {{1}, {2, 3}, {}, {4, 5, 6}};   // literal jagged array; row 2 is empty

new int[4][] with the second dimension omitted creates only the outer array; each row is null until assigned. Pascal's triangle, adjacency lists, and "rows read from input of varying width" are natural jagged arrays.

Consequences: grid[0].length is not "the width" unless you know the grid is rectangular; a row may be null (NPE on grid[r].length); and grid[r] = grid[0] makes two rows the same array.

Rows are references

int[][] a = new int[2][2];
int[] row = a[0];
row[1] = 9;                       // a[0][1] is now 9 — row IS a[0]

int[][] b = a.clone();            // shallow: b is a new outer array, but b[0] == a[0]
b[0][0] = 5;                      // a[0][0] is also 5

clone(), Arrays.copyOf and System.arraycopy on the outer array copy the row references, not the rows. A deep copy is a loop: for (r …) b[r] = a[r].clone(); (or Arrays.stream(a).map(int[]::clone).toArray(int[][]::new)).

The same applies to printing and comparing: Arrays.toString(grid) prints [[I@…, [I@…]; use Arrays.deepToString(grid). Arrays.equals(a, b) compares row references; Arrays.deepEquals(a, b) compares contents.

Three and more dimensions

int[][][] cube = new int[2][3][4]; — an array of 2 arrays of 3 arrays of 4 ints. Same rules, one more level. Beyond three dimensions, consider a flat array with computed indices.

Flat arrays as grids

For performance-critical grids (image processing, dynamic programming tables), a single int[rows * cols] indexed as a[r * cols + c] avoids the per-row indirection and the extra objects, and keeps everything in one contiguous block. It is less readable; use it when measurement says so.

Reading a grid from input

int rows = in.nextInt(), cols = in.nextInt();
int[][] g = new int[rows][cols];
for (int r = 0; r < rows; r++)
    for (int c = 0; c < cols; c++)
        g[r][c] = in.nextInt();

For a character grid (mazes, boards): char[][] board = new char[rows][]; for (r …) board[r] = in.next().toCharArray(); — each line becomes a row.

Common patterns

  • Transpose (rectangular): t[c][r] = g[r][c] with t = new int[cols][rows].
  • Neighbours: check bounds 0 <= nr && nr < rows && 0 <= nc && nc < cols before g[nr][nc]; direction arrays int[] dr = {-1, 1, 0, 0}, dc = {0, 0, -1, 1} avoid four copies of the check.
  • Row sums / column sums: two nested loops; column sums accumulate into colSum[c] while walking rows.
  • Diagonals: main diagonal g[i][i]; anti-diagonal g[i][n - 1 - i].

Interview angle

  • "Is int[][] a matrix?" An array of arrays; rows are separate objects and may differ in length.
  • "How many objects does new int[3][4] create?" Four.
  • "Why does clone() on a 2D array not copy the contents?" It copies the outer array's references to the same rows.
  • "How do you print a 2D array?" Arrays.deepToString.

Key takeaways

  • int[][] is an array of row arrays; grid.length is rows, grid[r].length is that row's length.
  • new int[n][] leaves rows null; rows may be jagged and may be shared.
  • Copying, comparing and printing the outer array is shallow — use deepToString, deepEquals, and clone each row.
  • Iterate row-major; bounds-check neighbours with direction arrays.

Common questions

What is a jagged array in Java?

A jagged array is a 2D array whose rows have different lengths. new int[4][] creates only the outer array with every row null, and each row is then assigned on its own, for example triangle[r] = new int[r + 1] for Pascal's triangle.

How do you print a 2D array in Java?

Use Arrays.deepToString(grid). Arrays.toString(grid) prints only each row's type code and hash, such as [I@1b6d3586, because the outer array's elements are arrays; deepToString descends into every row and prints its values.

How do you deep copy a 2D array in Java?

Clone each row: create a new outer array and assign copy[r] = grid[r].clone() in a loop. grid.clone(), Arrays.copyOf and System.arraycopy on the outer array copy only the row references, so the copy and the original would share their rows.

How many objects does new int[3][4] create in Java?

Four: the outer int[3] array and three int[4] row arrays. Each row is a separate object on the heap, which is why rows can be shared, replaced or left null.

How do you get the number of rows and columns of a 2D array in Java?

grid.length is the number of rows and grid[r].length is the length of row r. grid[0].length is the column count only when the array is rectangular; in a jagged array each row must be measured separately.

Exercises

Row and column sums

Read integers R and C, then an R × C grid of integers. Print R lines row <i>=<sum>, then C lines col <j>=<sum>, then diag=<sum of cells where row == col>.

Example: 2 3 then 1 2 3 / 4 5 6 →

row 0=6
row 1=15
col 0=5
col 1=7
col 2=9
diag=6

Transpose and trace

Read r and c and an r × c matrix. Print its transpose (c rows of r values, space-separated), then trace=<sum of m[i][i] for i < min(r, c)> and symmetric=<true if r == c and the matrix equals its transpose>.

Example: 2 3 then 1 2 3 / 4 5 6 →

1 4
2 5
3 6
trace=6
symmetric=false

In this module: Arrays

← Arrays — fixed-size, typed, zero-based · The Arrays class and System.arraycopy →