Поскольку элемент массива может быть ссылкой на объект, а массивы являются объектами, то элементы массива могут сами ссылаться на другие массивы. В Java массив массивов может быть определен следующим образом:
<тип_элемента>[][]...[] <имя_массива>;
или
<тип_элемента> <имя_массива>[][]...[];
Фактически последовательность пар квадратных скобок [ ]
, указывающая количество, может располагаться или после <типа элемента>, или после <имени массива>. Массивы массивов также иногда называют многомерными массивами. Следующие объявления эквивалентны.
int[][] mXnArray; // 2-мерный массив
int[] mXnArray[]; // 2-мерный массив
int mXnArray[][]; // 2-мерный массив
Обычно объединяют объявление с созданием многомерного массива.
int[][] mXnArray = new int[4][5]; // 4 x 5 матрица целых чисел
Предыдущее объявление создает массив mXnArray
из четырех элементов, причем каждый элемент массива является массивом (строкой) из пяти целых значений. Идея строк и столбцов часто применяется в описании 2-мерного массива, который, в свою очередь, часто называют матрицей. Но подобная интерпретация не навязывается языком программирования Java.
Каждая строка предыдущей матрицы обозначается mXnArray[i]
, 0 ≤ i < 4
. К каждому элементу в i
-й строке mXnArray
[i]
можно обращаться mXnArray
[i][j]
, где 0 ≤ j < 5
. Количество строк задается mXnArray.length
, в нашем случае 4
, и количество значений в i
-й строке задается mXnArray[i].length
, в нашем случае 5
для всех строк, где 0 ≤ i < 4
.
Многомерные массивы можно также создать и явно проинициализировать при помощи блока инициализации, который мы рассмотрели для простых массивов. Обратите внимание, что каждая строка является массивом, значения которого определяются через блок инициализации.
double[][] identityMatrix = {
{ 1.0, 0.0, 0.0, 0.0 }, // 1. строка
{ 0.0, 1.0, 0.0, 0.0 }, // 2. строка
{ 0.0, 0.0, 1.0, 0.0 }, // 3. строка
{ 0.0, 0.0, 0.0, 1.0 } // 4. строка
}; // 4 x 4 вещественная матрица
Не требуется, чтобы массивы в многомерном массиве были одинаковой длины, массивов pizzaGalore
в следующем коде будет содержать пять строк, четыре из которых имеют разные длины, а пятая не создается вообще.
Pizza[][] pizzaGalore = {
{ new Pizza(), null, new Pizza() }, // 1. строка в массиве из 3 элементов
{ null, new Pizza() }, // 2. строка в массиве из 2 элементов
new Pizza[1], // 3. строка в массиве из 1 элементов
{ }, // 4. строка в массиве из 0 элементов
null // 5. Строка пока не создана
};
Если многомерные массивы создаются оператором new
, то длину глубоко вложенных массивов можно опустить. В таком случае эти массивы остаются несозданными. Например, массив массивов, представляющий комнаты на этажах в гостиницах на улицах города может быть типа HotelRoom[][][][]
. Соответственно слева направо квадратные скобки представляют индексы для улицы, отеля, этажа и комнаты. Такой 4-мерный массив массивов может создаваться по частям, начиная с самого левого измерения и до правого.
HotelRoom[][][][] rooms = new HotelRoom[10][5][][]; // Только улицы и отели
В объявлении выше массив массивов комнат создается по частям — сначала 10 улиц, каждая из них имеет пять отелей. Добавление этажей и комнат в конкретную гостиницу на определенной улице:
rooms[0][0] = new HotelRoom[3][]; // 3 этажа в 1-й гостинице на 1-й улице
rooms[0][0][0] = new HotelRoom[8]; // 8 комнат на 1-м этаже в этой гостинице
rooms[0][0][0][0] = new HotelRoom(); // Инициализируем 1-ю комнату на этом этаже.
В следующем коде создается матрица, в которой в первой строке содержится один элемент, во второй строке — два элемента, а в третьей строке содержится три элемента. Обратите внимание, что внешний массив создается первым. Массив второго уровня создается в цикле, который заполняет массив построчно. Элементы массива будут неявно инициализированы значением по умолчанию типа double(0.0D)
. На рис. 4.1 изображена матрица элементов, которые были явно инициализированы.
double[][] matrix = new double[3][]; // без строк
for (int i = 0; i < matrix.length; ++i)
matrix[i] = new double[i + 1]; // создание строки
Существуют другие способы инициализации такого массива массивов, первый из которых заключается в применении блоков инициализации, а второй — в использовании анонимного массива массивов, как показано ниже.
double[][] matrix2 = {
{ 0.0 }, // 1 строка
{ 0.0, 0.0 }, // 2 строка
{ 0.0, 0.0, 0.0 } // 3 строка
};
double[][] matrix3 = new double[][]{
{ 0.0 },
{ 0.0, 0.0 },
{ 0.0, 0.0, 0.0 }
};
Тип переменной matrix
— double[][]
(т.е. двумерный массив значений типа double
). Типом переменной matrix[i](0 ≤ i < matrix.length)
является double[]
(т.е. одномерный массив значений типа double
). Типом переменной matrix[i][j]
(0 ≤ i < matrix.length
и 0 ≤ j < matrix[i].length)
является double
(т.е. простая переменная типа double
).
Вложенные циклы естественным образом подходят для управления многомерными массивами. В примере 4.3 объявлена и создана в строке (1) прямоугольная матрица 4x3
типа int
. В программе происходит поиск минимального значения в матрице. Внешний цикл в строке (2) проходит по строкам mXnArray[i], 0 ≤ i < mXnArray.length
, внутренний цикл в строке (3) проходит по очереди по элементам каждой строки mXnArray[i][j], 0 ≤ j < mXnArray[i].length)
. Внешний цикл выполняется mXnArray.length
раз или 4 раза, внутренний цикл выполняется (mXnArray.length) x (mXnArray[i].length)
раз или 12
, потому что все строки имеют одинаковую длину, равную 3
.
Пример 4.3. Применение многомерных массивов
class MultiArrays {
public static void main(String[] args) {
// Объявление и создание матрицы M X N
int[][] mXnArray = { // (1)
{ 16, 7, 12 }, // 1. row
{ 9, 20, 18 }, // 2. row
{ 14, 11, 5 }, // 3. row
{ 8, 5, 10 } // 4. row
}; // Матрица 4 x 3
// Поиск минимального значения в матрице M X N
int min = mXnArray[0][0];
for (int i = 0; i < mXnArray.length; ++i) // (2)
// Поиск минимума в mXnArray[i], т.е. в строке с индексом i.
for (int j = 0; j < mXnArray[i].length; ++j) // (3)
min = Math.min(min, mXnArray[i][j]);
System.out.println("Minimum value: " + min);
}
}
Вывод программы:
Minimum value: 5
Инициализация и использование массивов | Классы и методы |