Фрагмент лекции JavaRush - университета.
— Приветствую, Амиго!
— Здравствуй, Риша!
— Ты уже знаешь кое-что о массивах, даже задачи уже успел порешать, я надеюсь. Но ты знаешь далеко не всё. Вот например, ещё один интересный факт о массивах. Они — массивы — бывают не только одномерными (линейными), но и двумерными.
— Эмм… И что это значит?
— А это значит, что ячейки массива можно представить не только в виде столбца (или строки), но и в виде прямоугольной таблицы.
int[][]имя = new int[ширина][высота];
— Где имя — это имя переменной-массива, ширина — это ширина таблицы (в ячейках), а высота — это высота таблицы. Посмотри на пример:
|
Создаем двумерный массив: два столбца и 5 строк. В ячейку (1,1) записываем 5. |
— Вот как это будет выглядеть в памяти:

— Кстати, для двумерных массивов можно тоже использовать быструю инициализацию:
// длины месяцев года поквартально
int[][] months = { {31, 28, 31}, {30, 31, 30}, {31, 31, 30}, {31, 30, 31} };
— Хм… интересно получается. Если представить что в первых внутренних скобках один элемент, в следующих второй… Выходит, двумерный массив — это как бы массив массивов?
— Какой же ты смышлёный ученик! Именно так. Первый его элемент — одномерный массив {31, 28, 31}
, второй — {30, 31, 30}
, и так далее. Но к этому мы вернёмся чуть позднее в этой лекции. А пока постарайся представить двумерный массив в виде таблицы со строками и столбцами, которые образуют ячейки на пересечении.
— Представил. Кстати, а для чего их вообще используют, эти двумерные массивы?
— Программисту часто может понадобиться двумерный массив. Если присмотреться, реализация практически любой настольной игры — это же готовый двумерный массив: «Шахматы», «Шашки», «Крестики-Нолики», «Морской бой»:

— Я понял! Игровое поле «Шахмат» или «Морского боя» просто идеально ложится на двумерные массивы!
— Да, только в качестве координат клеток нужно будет использовать только числа. Не «пешка e2 -> e4», а «пешка (4,1) -> (4,3)». Тебе как программисту будет даже проще.
Расположение элементов в массивах: (x,y) или (y,x)
— С созданием двумерных массивов возникает интересная дилемма. Когда мы создаем массив new int[2][5];
у нас таблица «две строки и 5 столбцов» или все-таки «два столбца и 5 строк»?
— То есть, не совсем понятно, задаём ли мы сначала «ширину», а потом «высоту»... или наоборот, сначала «высоту», а потом — «ширину»?
— Да, дилемма состоит именно в этом. И однозначного ответа нет.
— Что же делать?
— Для начала важно понять, как на самом деле наш двумерный массив хранится в памяти. Естественно, никаких таблиц в самой памяти компьютера нет: все байты памяти пронумерованы как 0, 1, 2, ... Это для нас таблица 2×5, а в памяти — просто 10 ячеек и всё. Без разделения на строки и столбцы.
— Это я понял. Как тогда определить, какая координата первая — ширина или высота?
— Рассмотрим первый вариант. Сначала ширина, потом высота. Аргумент в пользу такого подхода: все в школе учили математику, и что из пары координат сначала указывается «x» (то есть ширина), а затем «y» (высота). И это не просто школьный стандарт — это вообще стандарт в математике. Против царицы наук, как говорится, не попрешь.
— Так что? Раз не попрёшь, значит, сначала «ширина», а затем — «высота»?
— Есть интересный аргумент и в пользу гипотезы «сначала высота, затем ширина». Исходит этот аргумент из быстрой инициализации двумерных массивов. Ведь если мы захотим инициализировать наш массив, напишем этот код как:
// Важная матрица с данными
int[][] matrix = { {1, 2, 3, 4, 5}, {1, 2, 3, 4, 5} };
— И что с того?
— Ничего не заметил? А если так:
// Важная матрица с данными
int[][] matrix = {
{1, 2, 3, 4, 5},
{1, 2, 3, 4, 5}
};
— Если мы напишем наши данные в коде построчно, то получим таблицу, у которой 2 строки и 5 столбцов.
— Теперь вижу. 2 — это высота, и 5 — ширина… И как же тогда поступать?
— Тебе решать, как удобнее. Главное, чтобы все программисты, работающие над одним проектом, придерживались одного подхода.
— Если ты будешь работать над проектом, где много инициализированных двумерных массивов в коде, то скорее всего там все будут отталкиваться от быстрой инициализации данных и будет стандарт «высота»-«ширина».
— Если же ты попадешь в проект, где много математики и работают с координатами (например, работа с игровыми движками), там скорее всего будут придерживаться подхода «ширина»-«высота».
Устройство двумерных массивов
— Итак, ты помнишь, какую особенность структуры двумерных массивов ты подметил в начале лекции?
— Да, то, что двумерные массивы — это на самом деле массивы массивов!
— Совершенно верно. Другими словами, если в случае с обычным массивом «переменная-массив хранит ссылку на контейнер, который хранит элементы массива», то в случае с двумерными массивами у нас ситуация немного взрывоопаснее: переменная-двумерный-массив хранит ссылку на контейнер, который хранит ссылки на одномерные массивы. Это лучше один раз увидеть, чем сто раз попробовать объяснить:

— Слева у нас «переменная-двумерный-массив», которая хранит ссылку на «объект-двумерный-массив». В середине — «объект двумерный массив», в ячейках которого хранятся ссылки на одномерные массивы — строки двумерного массива. Ну и справа ты можешь видеть четыре одномерных массива — строки нашего двумерного массива. Это то, как на самом деле устроены двумерные массивы.
— Здорово! Но что нам это даёт?
— Поскольку «контейнер контейнеров» хранит ссылки на «массивы-строки», мы можем очень быстро и просто менять строки местами. Чтобы получить доступ к «контейнеру контейнеров», нужно просто указать один индекс вместо двух. Пример:
int[][] data = new int[2][5];
int[] row1 = data[0];
int[] row2 = data[1];
— Посмотри на код ниже. С его помощью мы можем поменять строки местами:
|
Двумерный массив В matrix[0] у нас хранится ссылка на первую строку.Меняем ссылки местами. В итоге массив matrix выглядит так:
|
— Понял. Работает как обычный swap двух элементов.
— Так и есть. Ну а если ты обращаешься к ячейке двумерного массива, но после имени массива указываешь только один индекс, ты таким образом обратишься к контейнеру контейнеров, в ячейках которого хранятся ссылки на обычные одномерные массивы.
— Всё кажется логичным и понятным. Спасибо за лекцию, Риша!
— Пожалуйста. Применяй на практике с умом.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ