Complete guide to multi-dimensional arrays in Java covering 2D arrays, 3D arrays, matrix operations, memory layout, row-major storage, traversal techniques, and practical applications.
What is a Multi-Dimensional Array?
A multi-dimensional array is an array of arrays. While a 1D array is like a single row of elements, a 2D array is like a table with rows and columns, and a 3D array is like a cube with layers, rows, and columns.
In Java, multi-dimensional arrays are implemented as arrays that contain references to other arrays. This is different from languages like C where the entire 2D array is one contiguous block. In Java, each row is a separate array object in the heap.
Real-World Analogies
| Dimension | Analogy | Example Use |
|---|
| 1D | A single row of lockers | List of scores |
| 2D | A spreadsheet (rows × columns) | Grade table, game board |
| 3D | A Rubik's cube (layers × rows × columns) | 3D graphics, video frames |
Two-Dimensional Array (2D Array)
A 2D array is the most commonly used multi-dimensional array. It represents data in a tabular format with rows and columns.
Visual Representation
2D Array: matrix[3][4] (3 rows, 4 columns)
Col 0 Col 1 Col 2 Col 3
+-------+-------+-------+-------+
Row 0 | 10 | 20 | 30 | 40 |
+-------+-------+-------+-------+
Row 1 | 50 | 60 | 70 | 80 |
+-------+-------+-------+-------+
Row 2 | 90 | 100 | 110 | 120 |
+-------+-------+-------+-------+
Access: matrix[1][2] = 70 (row 1, column 2)
Declaration
// Style 1 (Recommended)
dataType[][] arrayName;
// Style 2
dataType arrayName[][];
// Style 3
dataType[] arrayName[];
Creation
// Creates a 3×4 array (3 rows, 4 columns)
int[][] matrix = new int[3][4];
Memory Layout of a 2D Array
int[][] matrix = new int[3][4];
Memory Diagram:
STACK HEAP
+----------+
| matrix |——————> +--------+--------+--------+
| (ref) | | row[0] | row[1] | row[2] | <- Array of references
+----------+ +---+----+---+----+---+----+
| | |
v v v
+--+--+--+--+ +--+--+--+--+ +--+--+--+--+
| 0| 0| 0| 0| | 0| 0| 0| 0| | 0| 0| 0| 0|
+--+--+--+--+ +--+--+--+--+ +--+--+--+--+
Row 0 Row 1 Row 2
Key Insight: matrix is a reference to an array of 3 references. Each of those references points to a separate int[4] array. This means rows can potentially have different lengths (jagged arrays).
Initialization Methods
Method 1: Array Literal
public class TwoDArrayInit {
public static void main(String[] args) {
int[][] matrix = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
System.out.println("Rows: " + matrix.length);
System.out.println("Columns in row 0: " + matrix[0].length);
System.out.println("Element at [1][2]: " + matrix[1][2]);
}
}
Rows: 3
Columns in row 0: 4
Element at [1][2]: 7
Method 2: Using Loops
public class TwoDLoopInit {
public static void main(String[] args) {
int[][] table = new int[5][5];
// Multiplication table
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
table[i][j] = (i + 1) * (j + 1);
}
}
// Print the table
System.out.println("Multiplication Table (1-5):");
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
System.out.printf("%4d", table[i][j]);
}
System.out.println();
}
}
}
Multiplication Table (1-5):
1 2 3 4 5
2 4 6 8 10
3 6 9 12 15
4 8 12 16 20
5 10 15 20 25
import java.util.Scanner;
public class TwoDInput {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Enter rows: ");
int rows = sc.nextInt();
System.out.print("Enter columns: ");
int cols = sc.nextInt();
int[][] matrix = new int[rows][cols];
System.out.println("Enter elements:");
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
matrix[i][j] = sc.nextInt();
}
}
System.out.println("\nMatrix:");
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
System.out.print(matrix[i][j] + "\t");
}
System.out.println();
}
sc.close();
}
}
Enter rows: 2
Enter columns: 3
Enter elements:
1 2 3 4 5 6
Matrix:
1 2 3
4 5 6
Traversal of 2D Arrays
Row-wise Traversal
public class RowWise {
public static void main(String[] args) {
int[][] matrix = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
System.out.println("Row-wise traversal:");
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
System.out.print(matrix[i][j] + " ");
}
System.out.println();
}
}
}
Row-wise traversal:
1 2 3
4 5 6
7 8 9
Column-wise Traversal
public class ColumnWise {
public static void main(String[] args) {
int[][] matrix = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
System.out.println("Column-wise traversal:");
for (int j = 0; j < matrix[0].length; j++) {
for (int i = 0; i < matrix.length; i++) {
System.out.print(matrix[i][j] + " ");
}
System.out.println();
}
}
}
Column-wise traversal:
1 4 7
2 5 8
3 6 9
Using Enhanced For Loop
public class ForEach2D {
public static void main(String[] args) {
int[][] matrix = {{10, 20, 30}, {40, 50, 60}, {70, 80, 90}};
for (int[] row : matrix) { // Each row is a 1D array
for (int element : row) { // Each element in the row
System.out.print(element + " ");
}
System.out.println();
}
}
}
10 20 30
40 50 60
70 80 90
Matrix Operations
Matrix Addition
Two matrices can be added if they have the same dimensions. Each element is added to the corresponding element.
import java.util.Arrays;
public class MatrixAddition {
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}};
int rows = A.length;
int cols = A[0].length;
int[][] C = new int[rows][cols];
// Addition: C[i][j] = A[i][j] + B[i][j]
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
C[i][j] = A[i][j] + B[i][j];
}
}
System.out.println("Matrix A + B:");
for (int[] row : C) {
System.out.println(Arrays.toString(row));
}
}
}
Matrix A + B:
[10, 10, 10]
[10, 10, 10]
[10, 10, 10]
Matrix Multiplication
Matrix multiplication requires: columns of A == rows of B. Result has dimensions: rows of A × columns of B.
import java.util.Arrays;
public class MatrixMultiplication {
public static void main(String[] args) {
int[][] A = {{1, 2, 3}, {4, 5, 6}}; // 2×3
int[][] B = {{7, 8}, {9, 10}, {11, 12}}; // 3×2
int rowsA = A.length; // 2
int colsA = A[0].length; // 3
int colsB = B[0].length; // 2
int[][] C = new int[rowsA][colsB]; // Result: 2×2
for (int i = 0; i < rowsA; i++) {
for (int j = 0; j < colsB; j++) {
for (int k = 0; k < colsA; k++) {
C[i][j] += A[i][k] * B[k][j];
}
}
}
System.out.println("A (2x3):");
for (int[] row : A) System.out.println(Arrays.toString(row));
System.out.println("\nB (3x2):");
for (int[] row : B) System.out.println(Arrays.toString(row));
System.out.println("\nA × B (2x2):");
for (int[] row : C) System.out.println(Arrays.toString(row));
}
}
A (2x3):
[1, 2, 3]
[4, 5, 6]
B (3x2):
[7, 8]
[9, 10]
[11, 12]
A × B (2x2):
[58, 64]
[139, 154]
Dry Run for C[0][0]:
C[0][0] = A[0][0]*B[0][0] + A[0][1]*B[1][0] + A[0][2]*B[2][0]
= 1*7 + 2*9 + 3*11
= 7 + 18 + 33
= 58
Matrix Transpose
Transpose swaps rows and columns: T[j][i] = M[i][j]
import java.util.Arrays;
public class MatrixTranspose {
public static void main(String[] args) {
int[][] matrix = {{1, 2, 3}, {4, 5, 6}}; // 2×3
int rows = matrix.length;
int cols = matrix[0].length;
int[][] transpose = new int[cols][rows]; // 3×2
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
transpose[j][i] = matrix[i][j];
}
}
System.out.println("Original (2x3):");
for (int[] row : matrix) System.out.println(Arrays.toString(row));
System.out.println("\nTranspose (3x2):");
for (int[] row : transpose) System.out.println(Arrays.toString(row));
}
}
Original (2x3):
[1, 2, 3]
[4, 5, 6]
Transpose (3x2):
[1, 4]
[2, 5]
[3, 6]
Diagonal Elements
public class MatrixDiagonal {
public static void main(String[] args) {
int[][] matrix = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 16}
};
int n = matrix.length;
// Primary diagonal: elements where row == column
System.out.print("Primary diagonal: ");
int primarySum = 0;
for (int i = 0; i < n; i++) {
System.out.print(matrix[i][i] + " ");
primarySum += matrix[i][i];
}
System.out.println("(Sum: " + primarySum + ")");
// Secondary diagonal: elements where row + column == n - 1
System.out.print("Secondary diagonal: ");
int secondarySum = 0;
for (int i = 0; i < n; i++) {
System.out.print(matrix[i][n - 1 - i] + " ");
secondarySum += matrix[i][n - 1 - i];
}
System.out.println("(Sum: " + secondarySum + ")");
}
}
Primary diagonal: 1 6 11 16 (Sum: 34)
Secondary diagonal: 4 7 10 13 (Sum: 34)
Three-Dimensional Array (3D Array)
A 3D array can be visualized as a stack of 2D tables or a cube.
public class ThreeDArray {
public static void main(String[] args) {
// 2 layers, 3 rows, 4 columns
int[][][] cube = new int[2][3][4];
// Initialize with sequential values
int value = 1;
for (int layer = 0; layer < 2; layer++) {
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 4; col++) {
cube[layer][row][col] = value++;
}
}
}
// Print
for (int layer = 0; layer < 2; layer++) {
System.out.println("Layer " + layer + ":");
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 4; col++) {
System.out.printf("%4d", cube[layer][row][col]);
}
System.out.println();
}
System.out.println();
}
}
}
Layer 0:
1 2 3 4
5 6 7 8
9 10 11 12
Layer 1:
13 14 15 16
17 18 19 20
21 22 23 24
Searching in 2D Array
public class Search2D {
public static void main(String[] args) {
int[][] matrix = {
{10, 20, 30},
{40, 50, 60},
{70, 80, 90}
};
int target = 50;
boolean found = false;
int foundRow = -1, foundCol = -1;
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
if (matrix[i][j] == target) {
found = true;
foundRow = i;
foundCol = j;
break;
}
}
if (found) break;
}
if (found) {
System.out.println(target + " found at position [" + foundRow + "][" + foundCol + "]");
} else {
System.out.println(target + " not found");
}
}
}
50 found at position [1][1]
Row Sum and Column Sum
public class RowColSum {
public static void main(String[] args) {
int[][] matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// Row sums
System.out.println("Row sums:");
for (int i = 0; i < matrix.length; i++) {
int sum = 0;
for (int j = 0; j < matrix[i].length; j++) {
sum += matrix[i][j];
}
System.out.println("Row " + i + ": " + sum);
}
// Column sums
System.out.println("\nColumn sums:");
for (int j = 0; j < matrix[0].length; j++) {
int sum = 0;
for (int i = 0; i < matrix.length; i++) {
sum += matrix[i][j];
}
System.out.println("Col " + j + ": " + sum);
}
}
}
Row sums:
Row 0: 6
Row 1: 15
Row 2: 24
Column sums:
Col 0: 12
Col 1: 15
Col 2: 18
Printing 2D Array using Arrays.deepToString()
import java.util.Arrays;
public class DeepToString {
public static void main(String[] args) {
int[][] matrix = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
// Arrays.toString() doesn't work for 2D
System.out.println("toString: " + Arrays.toString(matrix)); // Shows references
// Arrays.deepToString() works for multi-dimensional
System.out.println("deepToString: " + Arrays.deepToString(matrix));
}
}
toString: [[I@1b6d3586, [I@4554617c, [I@74a14482]
deepToString: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Boundary Elements of a Matrix
public class BoundaryElements {
public static void main(String[] args) {
int[][] matrix = {
{1, 2, 3, 4, 5},
{6, 7, 8, 9, 10},
{11, 12, 13, 14, 15},
{16, 17, 18, 19, 20}
};
int rows = matrix.length;
int cols = matrix[0].length;
System.out.println("Boundary elements:");
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (i == 0 || i == rows - 1 || j == 0 || j == cols - 1) {
System.out.printf("%4d", matrix[i][j]);
} else {
System.out.print(" ");
}
}
System.out.println();
}
}
}
Boundary elements:
1 2 3 4 5
6 10
11 15
16 17 18 19 20
Common Mistakes
1. Confusing Row and Column Count
int[][] matrix = new int[3][4]; // 3 rows, 4 columns
// matrix.length = 3 (number of rows)
// matrix[0].length = 4 (number of columns in row 0)
// DON'T confuse these!
2. Using Arrays.toString() for 2D Arrays
int[][] matrix = {{1,2},{3,4}};
// System.out.println(Arrays.toString(matrix)); // Shows garbage references
System.out.println(Arrays.deepToString(matrix)); // Shows actual values
3. Assuming All Rows Have Same Length
int[][] arr = new int[3][];
arr[0] = new int[2];
arr[1] = new int[5]; // Different lengths!
// Always use matrix[i].length for inner loop, NOT matrix[0].length
4. Off-by-One in Nested Loops
// WRONG: using matrix.length for both loops
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix.length; j++) {} // WRONG if not square!
}
// CORRECT:
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {} // Use row-specific length
}
5. Modifying 2D Array Size Expectation
int[][] m = new int[3][4];
// m.length = 3 (always — cannot change)
// But m[0] = new int[10] is valid! (replaces row 0 with bigger array)
Best Practices
- Use
matrix.length for rows and matrix[i].length for columns - Use
Arrays.deepToString() for printing multi-dimensional arrays - Use
Arrays.deepEquals() for comparing multi-dimensional arrays - Prefer rectangular arrays unless jagged is specifically needed
- Initialize with array literals when data is known at compile time
- Document array dimensions (e.g.,
// [students][subjects]) - Use helper methods for repeated matrix operations
- Consider ArrayList<ArrayList<Integer>> for dynamic 2D structures
- Validate dimensions before matrix operations (addition, multiplication)
- Use printf for formatted output when printing matrices
Interview Questions
Q1: How is a 2D array stored in memory in Java? A 2D array in Java is an array of references. The outer array holds references to inner 1D arrays. Each inner array is a separate object in heap memory. They are NOT guaranteed to be contiguous.
Q2: What is the difference between int[3][4] and int[4][3]? int[3][4] creates 3 rows with 4 columns each. int[4][3] creates 4 rows with 3 columns each. They have different structures and accessing patterns.
Q3: Can rows of a 2D array have different lengths in Java? Yes! Since a 2D array is an array of references to 1D arrays, each row can point to arrays of different sizes. This is called a jagged array.
Q4: What is the time complexity of matrix multiplication? O(n³) for standard matrix multiplication of two n×n matrices. There are optimized algorithms (Strassen's: O(n^2.807)) but they are rarely used in practice.
Q5: How do you pass a 2D array to a method? Declare the parameter as dataType[][] paramName. The entire 2D array reference is passed, so modifications inside the method affect the original.
Q6: What is Arrays.deepToString() used for? It converts multi-dimensional arrays to a readable string. Unlike Arrays.toString() which only works for 1D arrays, deepToString() recursively processes nested arrays.
Q7: What is row-major and column-major order? Row-major stores elements row by row (Java's approach). Column-major stores elements column by column (Fortran's approach). This affects cache performance when traversing.
Q8: How do you create an identity matrix? Set diagonal elements to 1: if (i == j) matrix[i][j] = 1; else matrix[i][j] = 0;
Q9: What is the space complexity of an m×n matrix? O(m × n) for the elements plus O(m) for the row references, so effectively O(m × n).
Q10: Can you sort a 2D array by a specific column? Yes, using Arrays.sort(matrix, (a, b) -> a[colIndex] - b[colIndex]) with a custom comparator.