1. Введение
Представьте себе обычный массив как длинный ящик из-под пиццы, где все кусочки лежат в ряд — вкусно, но однообразно.
А теперь представим расписание работ или шахматную доску. Там уже всё организовано в строки и столбцы — то есть в таблицу. Вот это и есть классическая задача для двумерного массива.
В реальной жизни двумерные массивы встречаются на каждом шагу:
- Таблицы с зарплатами сотрудников (строки — сотрудники, столбцы — месяцы).
- Картинка на экране (каждая "клетка" — цвет пикселя, у нее две координаты: X и Y).
- Матричные вычисления и обработка данных.
- Шахматная доска или поле для крестиков-ноликов.
Иногда двумерный массив называют матрицей (это название пришло из математики).
Есть очень много мест, где вам как программисту может понадобиться двумерный массив. Реализация практически любой настольной игры — это готовый двумерный массив: «Шахматы», «Шашки», «Крестики-нолики», «Морской бой»:

Игровое поле «Шахмат» или «Морского боя» такое, что оно просто идеально ложится на двумерные массивы, где в качестве координат клеток нужно будет использовать только числа. Не «пешка e2 ⟶ e4», а «пешка (4,1) ⟶ (4,3)». Вам как программисту так будет даже проще.
2. Синтаксис объявления двумерных массивов
Страшно только до первого объявления! Разбираемся шаг за шагом.
Общее правило
тип[][] имяМассива;
Здесь две пустые [] скобки — не ошибка компилятора после ночи с кофе, а указание: массив двумерный.
Примеры
int[][] matrix;
double[][] gradesTable;
string[][] chessBoard;
Создание массива
Задаём размеры: количество строк и столбцов.
matrix = new int[3][4]; // 3 строки, 4 столбца
Это табличка 3x4: представьте Excel-таблицу с 3 строками и 4 колонками.
Можно сразу объявить переменную и создать двумерный массив:
int[][] matrix = new int[3][4];
Можно инициализировать сразу значениями (примерно как с одномерным):
int[][] example = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// Таблица 3 строки, 3 столбца
Визуальная схема
┌─────┬─────┬─────┬─────┐
│ 0 │ 1 │ 2 │ 3 │ ← столбцы (Columns)
├─────┼─────┼─────┼─────┤
│ 0,0 │ 0,1 │ 0,2 │ 0,3 │ ← строка 0 (Row 0)
├─────┼─────┼─────┼─────┤
│ 1,0 │ 1,1 │ 1,2 │ 1,3 │ ← строка 1 (Row 1)
├─────┼─────┼─────┼─────┤
│ 2,0 │ 2,1 │ 2,2 │ 2,3 │ ← строка 2 (Row 2)
└─────┴─────┴─────┴─────┘
Каждый элемент задаётся парой индексов [строка, столбец].
3. Индексация и доступ к элементам
В двумерном массиве для доступа к элементу указываются два индекса:
- Первый — номер строки.
- Второй — номер столбца.
// Во второй строке (индекс 1), третий столбец (индекс 2)
matrix[1][2] = 99;
Если кто-то привык к шахматам, напомню: индексация начинается с нуля. То есть первый элемент — это [0][0].
Запись и чтение
int[][] data = new int[5][2];
data[1][1] = 5; // запись
int value = data[1][1]; // чтение
Вот как это будет выглядеть в памяти:

4. Заполнение двумерного массива
Давайте напишем код, который заполнит матрицу последовательными числами от 1 до 12, чтобы стало понятно, как это работает.
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++;
}
}
Иллюстрация:
После выполнения:
┌────┬────┬────┬────┐
│ 1 │ 2 │ 3 │ 4 │
├────┼────┼────┼────┤
│ 5 │ 6 │ 7 │ 8 │
├────┼────┼────┼────┤
│ 9 │ 10 │ 11 │ 12 │
└────┴────┴────┴────┘
5. Устройство двумерных массивов
А сейчас вы узнаете, как на самом деле устроены двумерные массивы. Готовы?
Двумерные массивы — это на самом деле массивы массивов!
Другими словами, если в случае с обычным массивом «переменная-массив хранит ссылку на контейнер, который хранит элементы массива», то в случае с двумерными массивами у нас ситуация немного взрывоопаснее: переменная-двумерный-массив хранит ссылку на контейнер, который хранит ссылки на одномерные массивы. Это лучше один раз увидеть, чем сто раз попробовать объяснить:

Слева у нас «переменная-двумерный-массив», которая хранит ссылку на «объект-двумерный массив». В середине у нас «объект двумерный массив», в ячейках которого хранятся ссылки на одномерные массивы — строки двумерного массива. Ну и справа вы видите четыре одномерных массива — строки нашего двумерного массива.
Это то, как на самом деле устроены двумерные массивы. И такой подход даёт Java-программисту несколько преимуществ:
Во-первых, т.к. «контейнер контейнеров» хранит ссылки на «массивы-строки», мы можем очень быстро и просто менять строки местами. Чтобы получить доступ к «контейнеру контейнеров», нужно просто указать один индекс вместо двух. Пример:
int[][] data = new int[2][5];
int[] row1 = data[0];
int[] row2 = data[1];
Вот с помощью такого кода можно поменять строки местами:
// Важная матрица с данными
int[][] matrix = {
{1, 2, 3, 4, 5},
{5, 4, 3, 2, 1}
};
int[] tmp = matrix[0];
matrix[0] = matrix[1];
matrix[1] = tmp;
Если вы обращаетесь к ячейке двумерного массива, но после имени массива указываете только один индекс, вы таким образом обратитесь к контейнеру-контейнеров, в ячейках которого хранятся ссылки на обычные одномерные массивы.
6. Вывод двумерного массива на экран
Для вывода двумерной таблицы обычно используют двойной цикл — и это всё равно что рисовать лабиринт в консоли. Пример:
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(); // переход на новую строку
}
Пример вывода:
1 2 3 4
5 6 7 8
9 10 11 12
Кстати, вот тут вы научились красиво "рисовать" таблицы с помощью пары строк кода!
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ