Skip to main content

5.3 Multi-dimensional Arrays

The one-dimensional arrays covered so far store elements consecutively in a straight line. In Java, you can add additional brackets [][] to create two-dimensional, three-dimensional, or higher-dimensional data structures. They are useful for representing tables, matrices, image data, and more.

1. Declaring and Creating a 2D Array

A 2D array is mainly used to store table-style data organized in rows and columns.

Declaration

// type[][] variableName (recommended)
int[][] score;
String[][] table;

// Creation (4 rows, 3 columns)
int[][] score = new int[4][3]; // 12 spaces total

Initialization and Index Structure

// Initialize directly with values
int[][] score = {
{ 100, 90, 80 }, // row 0
{ 70, 85, 95 }, // row 1
{ 60, 75, 88 }, // row 2
{ 55, 65, 70 } // row 3
};

// Index: score[row][column]
System.out.println(score[0][0]); // 100 (row 0, column 0)
System.out.println(score[1][2]); // 95 (row 1, column 2)
System.out.println(score[3][1]); // 65 (row 3, column 1)

2. Memory Structure of a 2D Array

In Java, a 2D array is internally structured as an "array of arrays".

[Stack]        [Heap]
score ────→ [addr0][addr1][addr2][addr3] <- row reference array
| | | |
v v v v
[100,90,80] [70,85,95] [60,75,88] [55,65,70]

Because of this structure:

  • score.length: number of rows (4)
  • score[0].length: number of columns in row 0 (3)
int[][] score = new int[4][3];

System.out.println("Number of rows: " + score.length); // 4
System.out.println("Columns in row 0: " + score[0].length); // 3

3. Iterating Over a 2D Array

Use a nested for loop.

int[][] score = {
{ 100, 90, 80 },
{ 70, 85, 95 },
{ 60, 75, 88 },
{ 55, 65, 70 }
};

// Traditional for loop
for (int i = 0; i < score.length; i++) { // iterate rows
for (int j = 0; j < score[i].length; j++) { // iterate columns
System.out.printf("score[%d][%d]=%3d ", i, j, score[i][j]);
}
System.out.println();
}

System.out.println();

// Enhanced for loop
for (int[] row : score) { // iterate each row (1D array)
for (int val : row) { // iterate each element of the row
System.out.printf("%4d", val);
}
System.out.println();
}

Output:

score[0][0]=100  score[0][1]= 90  score[0][2]= 80
score[1][0]= 70 score[1][1]= 85 score[1][2]= 95
...

4. Jagged Array

Because Java 2D arrays are "arrays of arrays", each row can have a different length. Such an array is called a jagged array.

// Specify only the number of rows
int[][] jagged = new int[4][];
jagged[0] = new int[1]; // row 0: 1 element
jagged[1] = new int[2]; // row 1: 2 elements
jagged[2] = new int[3]; // row 2: 3 elements
jagged[3] = new int[4]; // row 3: 4 elements

// Fill with values
int value = 1;
for (int i = 0; i < jagged.length; i++) {
for (int j = 0; j < jagged[i].length; j++) {
jagged[i][j] = value++;
}
}

// Print
for (int[] row : jagged) {
for (int val : row) {
System.out.printf("%3d", val);
}
System.out.println();
}

Output:

  1
2 3
4 5 6
7 8 9 10

Jagged Array Use Case: Pascal's Triangle

// Pascal's triangle (5 rows)
int[][] pascal = new int[5][];
for (int i = 0; i < pascal.length; i++) {
pascal[i] = new int[i + 1];
pascal[i][0] = 1; // first element of each row
pascal[i][i] = 1; // last element of each row
for (int j = 1; j < i; j++) {
pascal[i][j] = pascal[i-1][j-1] + pascal[i-1][j];
}
}

for (int[] row : pascal) {
for (int val : row) {
System.out.printf("%4d", val);
}
System.out.println();
}

Output:

   1
1 1
1 2 1
1 3 3 1
1 4 6 4 1

5. 3D Arrays

3D arrays use [][][]. Practical examples include RGB image data and 3D spatial data.

// 3D array: [depth][row][column]
int[][][] cube = new int[2][3][4]; // 2 layers, 3 rows, 4 columns

// Assign values
for (int d = 0; d < cube.length; d++) {
for (int r = 0; r < cube[d].length; r++) {
for (int c = 0; c < cube[d][r].length; c++) {
cube[d][r][c] = d * 100 + r * 10 + c;
}
}
}

System.out.println(cube[0][1][2]); // 012 = 12
System.out.println(cube[1][2][3]); // 123

Practical Example: RGB Image Pixel Data

// Store RGB values of a simple 3x3 image
// pixels[row][column][channel] - channels: 0=R, 1=G, 2=B
int[][][] pixels = new int[3][3][3];

// Set red pixel at (0, 0)
pixels[0][0][0] = 255; // R
pixels[0][0][1] = 0; // G
pixels[0][0][2] = 0; // B

// Set green pixel at (1, 1)
pixels[1][1][0] = 0;
pixels[1][1][1] = 255;
pixels[1][1][2] = 0;

System.out.println("(0,0) RGB = (" +
pixels[0][0][0] + ", " + pixels[0][0][1] + ", " + pixels[0][0][2] + ")");
// Output: (0,0) RGB = (255, 0, 0)

6. 2D Array vs ArrayList<ArrayList<T>>

Comparisonint[][]ArrayList<ArrayList<Integer>>
ResizeNot possiblePossible
Memory efficiencyHighLow (overhead)
Access speedFastRelatively slow
Utility methodsNoneRich (add, remove, etc.)
Primitive type supportYes (int)No (must box as Integer)
// ArrayList<ArrayList<Integer>> example
import java.util.ArrayList;

ArrayList<ArrayList<Integer>> matrix = new ArrayList<>();
for (int i = 0; i < 3; i++) {
ArrayList<Integer> row = new ArrayList<>();
for (int j = 0; j < 3; j++) {
row.add(i * 3 + j);
}
matrix.add(row);
}

System.out.println(matrix.get(1).get(2)); // 5
Selection Guide
  • When size is fixed and performance matters: use int[][]
  • When size changes dynamically or rows may differ in length: use ArrayList<ArrayList<Integer>>

7. Practical Example 1: 3x3 Matrix Addition and Multiplication

import java.util.Arrays;

public class MatrixOperations {
// Print a matrix
static void printMatrix(int[][] m) {
for (int[] row : m) {
System.out.println(Arrays.toString(row));
}
}

// Matrix addition
static int[][] add(int[][] a, int[][] b) {
int rows = a.length;
int cols = a[0].length;
int[][] result = new int[rows][cols];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
result[i][j] = a[i][j] + b[i][j];
}
}
return result;
}

// Matrix multiplication (n x m * m x k = n x k)
static int[][] multiply(int[][] a, int[][] b) {
int n = a.length;
int m = a[0].length; // = b.length
int k = b[0].length;
int[][] result = new int[n][k];
for (int i = 0; i < n; i++) {
for (int j = 0; j < k; j++) {
for (int p = 0; p < m; p++) {
result[i][j] += a[i][p] * b[p][j];
}
}
}
return result;
}

public static void main(String[] args) {
int[][] a = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
int[][] b = {
{9, 8, 7},
{6, 5, 4},
{3, 2, 1}
};

System.out.println("Matrix A:");
printMatrix(a);

System.out.println("\nMatrix B:");
printMatrix(b);

System.out.println("\nA + B:");
printMatrix(add(a, b));

System.out.println("\nA * B:");
printMatrix(multiply(a, b));
}
}

Output:

Matrix A:
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]

Matrix B:
[9, 8, 7]
[6, 5, 4]
[3, 2, 1]

A + B:
[10, 10, 10]
[10, 10, 10]
[10, 10, 10]

A * B:
[30, 24, 18]
[84, 69, 54]
[138, 114, 90]

8. Practical Example 2: Calendar Printer

An example that constructs a 7-column (weekday) calendar using a 2D array.

public class CalendarPrinter {
public static void main(String[] args) {
// March 2025: 1st is Saturday (6), 31 days total
int startDay = 6; // 0=Sun, 1=Mon, ..., 6=Sat
int totalDays = 31;

// 6-row, 7-column calendar array (empty cells are 0)
int[][] calendar = new int[6][7];
int day = 1;

for (int row = 0; row < 6; row++) {
for (int col = 0; col < 7; col++) {
if (row == 0 && col < startDay) {
calendar[row][col] = 0; // empty cell
} else if (day <= totalDays) {
calendar[row][col] = day++;
}
}
}

// Print the calendar
System.out.println(" March 2025");
System.out.println("Sun Mon Tue Wed Thu Fri Sat");
System.out.println("---------------------------");

for (int[] week : calendar) {
for (int d : week) {
if (d == 0) {
System.out.print(" "); // empty cell
} else {
System.out.printf("%3d ", d);
}
}
// Don't print rows after the last day
boolean hasValue = false;
for (int d : week) if (d > 0) hasValue = true;
if (hasValue) System.out.println();
}
}
}

Output:

    March 2025
Sun Mon Tue Wed Thu Fri Sat
---------------------------
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
Pro Tips

Use Arrays.deepToString() to quickly inspect the contents of a 2D array.

import java.util.Arrays;

int[][] matrix = {{1, 2}, {3, 4}, {5, 6}};

System.out.println(Arrays.toString(matrix)); // prints addresses (wrong)
System.out.println(Arrays.deepToString(matrix)); // [[1, 2], [3, 4], [5, 6]]

A deep copy of a 2D array must copy each row individually.

int[][] original = {{1, 2, 3}, {4, 5, 6}};
int[][] deepCopy = new int[original.length][];
for (int i = 0; i < original.length; i++) {
deepCopy[i] = original[i].clone(); // copy each row individually
}