1. Introduction
Imagine a regular array as a long pizza box where all the slices lie in a row — tasty but monotonous.
Now think of a work schedule or a chessboard. There everything is organized into rows and columns — that is, into a table. This is a classic task for a two-dimensional array.
In real life, two-dimensional arrays are everywhere:
- Salary tables for employees (rows — employees, columns — months).
- An image on the screen (each “cell” is the pixel color; it has two coordinates: X and Y).
- Matrix calculations and data processing.
- A chessboard or a tic-tac-toe board.
Sometimes a two-dimensional array is called a matrix (the term comes from mathematics).
There are many places where, as a developer, you might need a two-dimensional array. The implementation of almost any board game is essentially a ready-made 2D array: “Chess”, “Checkers”, “Tic-tac-toe”, “Battleship”:

The playing field of “Chess” or “Battleship” fits perfectly into two-dimensional arrays, where you can use only numbers as cell coordinates. Not “pawn e2 ⟶ e4”, but “pawn (4,1) ⟶ (4,3)”. As a developer, that will actually be easier.
2. Syntax for declaring two-dimensional arrays
It’s only scary until the first declaration! Let’s go step by step.
General rule
type[][] arrayName;
Here, two empty [] brackets aren’t a compiler hiccup after a night with coffee, but an indication that the array is two-dimensional.
Examples
int[][] matrix;
double[][] gradesTable;
string[][] chessBoard;
Creating an array
Set the sizes: the number of rows and columns.
matrix = new int[3][4]; // 3 rows, 4 columns
This is a 3x4 table: imagine an Excel table with 3 rows and 4 columns.
You can declare the variable and create a two-dimensional array in one go:
int[][] matrix = new int[3][4];
You can initialize it with values right away (similar to a one-dimensional array):
int[][] example = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// A table with 3 rows and 3 columns
Visual diagram
┌─────┬─────┬─────┬─────┐
│ 0 │ 1 │ 2 │ 3 │ ← columns (Columns)
├─────┼─────┼─────┼─────┤
│ 0,0 │ 0,1 │ 0,2 │ 0,3 │ ← row 0 (Row 0)
├─────┼─────┼─────┼─────┤
│ 1,0 │ 1,1 │ 1,2 │ 1,3 │ ← row 1 (Row 1)
├─────┼─────┼─────┼─────┤
│ 2,0 │ 2,1 │ 2,2 │ 2,3 │ ← row 2 (Row 2)
└─────┴─────┴─────┴─────┘
Each element is specified by a pair of indices [row, column].
3. Indexing and element access
In a two-dimensional array, you specify two indices to access an element:
- The first is the row index.
- The second is the column index.
// In the second row (index 1), third column (index 2)
matrix[1][2] = 99;
If you’re used to chess notation, remember: indexing starts at zero. So the first element is [0][0].
Writing and reading
int[][] data = new int[5][2];
data[1][1] = 5; // write
int value = data[1][1]; // read
Here’s what it looks like in memory:

4. Filling a two-dimensional array
Let’s write code that fills the matrix with consecutive numbers from 1 to 12 to make it clear how this works.
int[][] matrix = new int[3][4];
int value = 1;
for (int row = 0; row < 3; row++)
{
for (int col = 0; col < 4; col++)
{
matrix[row][col] = value;
value++;
}
}
Illustration:
After execution:
┌────┬────┬────┬────┐
│ 1 │ 2 │ 3 │ 4 │
├────┼────┼────┼────┤
│ 5 │ 6 │ 7 │ 8 │
├────┼────┼────┼────┤
│ 9 │ 10 │ 11 │ 12 │
└────┴────┴────┴────┘
5. How two-dimensional arrays work
Now you’ll learn how two-dimensional arrays actually work. Ready?
Two-dimensional arrays are actually arrays of arrays!
In other words, with a regular array “the array variable holds a reference to a container that holds the array’s elements”, whereas with two-dimensional arrays the situation is a bit more explosive: the two-dimensional-array variable holds a reference to a container that holds references to one-dimensional arrays. It’s better to see it once than try to explain it a hundred times:

On the left, we have a “two-dimensional-array variable” that stores a reference to a “two-dimensional array object”. In the middle, we have the “two-dimensional array object”, whose cells store references to one-dimensional arrays — the rows of the two-dimensional array. And on the right, you can see four one-dimensional arrays — the rows of our two-dimensional array.
That’s how two-dimensional arrays really work. And this approach gives a Java developer several advantages:
First, since the “container of containers” stores references to the row arrays, we can swap rows very quickly and easily. To access the “container of containers”, you just specify one index instead of two. Example:
int[][] data = new int[2][5];
int[] row1 = data[0];
int[] row2 = data[1];
Here’s how you can swap rows using this code:
// An important matrix with data
int[][] matrix = {
{1, 2, 3, 4, 5},
{5, 4, 3, 2, 1}
};
int[] tmp = matrix[0];
matrix[0] = matrix[1];
matrix[1] = tmp;
If you access a two-dimensional array but specify only one index after the array name, you’ll be addressing the container-of-containers, whose cells store references to regular one-dimensional arrays.
6. Printing a two-dimensional array
To print a two-dimensional table, you usually use a nested loop — it’s like drawing a maze in the console. Example:
for (int row = 0; row < matrix.length; row++)
{
for (int col = 0; col < matrix[row].length; col++)
{
System.out.print(matrix[row][col] + "\t");
}
System.out.println(); // move to a new line
}
Sample output:
1 2 3 4
5 6 7 8
9 10 11 12
By the way, this is how you can neatly “draw” tables with just a few lines of code!
GO TO FULL VERSION