Инициализация массива в C может быть довольно сложной и проблематичной задачей. В C++, это стало безопаснее благодаря концепции «инициализации списка» (комментарий №6). Java не имеет такого понятия как «список», так как все объекты в нём являются экземплярами классов. Однако язык предоставляет свои собственные возможности для работы с массивами.
Массив представляет собой последовательность объектов или базовых данных одного типа, объединённых под одним общим именем. Определение и использование массива осуществляются через оператор индексации в квадратных скобках ([]
). Для определения массива достаточно указать тип данных, за которым следует пара пустых квадратных скобок:
int[] arr;
Кроме того, можно поместить квадратные скобки после имени переменной, что приведёт к тому же результату:
int arr[];
Этот синтаксис совместим с тем, который используют программисты на C и C++. Тем не менее, более естественным является первый вариант, поскольку он явно указывает, что arr
— это массив целых чисел. В данной книге будет использоваться именно этот синтаксис.Компилятор Java не позволяет нам указывать размер массива при его объявлении. Это снова приводит нас к вопросу о ссылках. В данном случае мы имеем лишь ссылку на массив, но ещё не выделили никакого пространства для хранения данных. Чтобы создать массив, необходимо использовать выражение инициализации. Инициализация массива может происходить в любом месте программы, однако существует специальное выражение инициализации, которое должно быть указано сразу при создании массива. Такое специальное выражение состоит из списка значений, заключённых в фигурные скобки. Выделение памяти (эквивалентное использованию new
) производится компилятором автоматически. Например:```
int[] array = { 1, 2, 3, 4, 5 };
Зачем вообще объявлять ссылку на массив без самого массива?
int[] anotherArray;
На самом деле, в Java возможно присвоение одного массива другому, поэтому следующее присваивание допустимо:
anotherArray = array;
Что мы действительно делаем здесь, это просто копируем ссылку на массив, как показано ниже:
//: Arrays.java // Массивы примитивных типов.
public class Arrays { public static void main(String[] args) { int[] array = { 1, 2, 3, 4, 5 }; int[] anotherArray; anotherArray = array; for(int i = 0; i < anotherArray.length; i++) anotherArray[i]++; for(int i = 0; i < array.length; i++) prt("array[" + i + "] = " + array[i]); } static void prt(String s) { System.out.println(s); } } ///:~
Когда вы видите, что `a1` получает начальное значение, а `a2` — нет; `a2` будет присвоено позже — в данном случае это другой массив.Здесь также появляются несколько новых вещей: все массивы имеют базовый член (будь то массив объектов или массив примитивных типов), который можно использовать для получения информации о количестве элементов в массиве, но не для изменения этого значения. Этот член называется `length`. Как и в C и C++, Java начинает отсчет с нулевого элемента, поэтому максимальный индекс элемента равен `length - 1`. При выходе за границы массива C и C++ будут "молча" принимать ошибку и позволят вам случайным образом использовать свою память, что является источником многих программных ошибок. Однако Java позволяет избежать этой проблемы путём генерации времени выполнения ошибки (также известной как "исключение", которое является темой главы 9).Очевидно, что проверка каждого доступа к массиву требует времени и дополнительного кода, который нельзя отключить. Это означает, что доступ к массиву может стать важным фактором снижения производительности программы — если они используются в критических местах. Однако, принимая во внимание безопасность доступа через Интернет и эффективность работы программиста, дизайнеры Java должны считать это приемлемым.
Что делать, если во время написания программы вы не знаете, сколько элементов потребуется в вашем массиве? В этом случае просто создайте элементы массива с помощью `new`. Здесь даже при создании массива примитивного типа `new` работает корректно (он не создаёт примитивные типы, кроме массивов):
```java
//: ArrayNew.java
// Создание массивов с помощью new.
import java.util.*;
public class ArrayNew {
static Random rand = new Random();
static int pRand(int mod) {
return Math.abs(rand.nextInt()) % mod + 1;
}
public static void main(String[] args) {
int[] a;
a = new int[pRand(20)];
prt("Длина a = " + a.length);
for(int i = 0; i < a.length; i++)
prt("a[" + i + "] = " + a[i]);
}
static void prt(String s) {
System.out.println(s);
}
} ///:~
```Поскольку размер массива определяется случайным образом (с использованием ранее определенного метода `pRand()`), очевидно, что создание массива происходит во время выполнения. Кроме того, из вывода данного примера видно, что элементы массива примитивных типов автоматически инициализируются значением по умолчанию (например, для чисел это 0, для `char` это `'\u0000'`, а для `boolean` это `false`). Конечно, массив может быть сразу определен и инициализирован в одной и той же команде, как показано ниже:```java
int[] a = new int[pRand(20)];
Если вы работаете с массивом объектов неприсваиваемого типа, вам всё равно придётся использовать new
. В этом случае мы снова столкнёмся с проблемами ссылок, так как создаём массив ссылок. Обратите внимание на упакованный тип данных Integer
, который является классом, а не примитивным типом данных:
//: ArrayClassObj.java
// Создание массива неприсваиваемых объектов.
import java.util.*;
public class ArrayClassObj {
static Random rand = new Random();
static int pRand(int mod) {
return Math.abs(rand.nextInt()) % mod + 1;
}
public static void main(String[] args) {
Integer[] a = new Integer[pRand(20)];
prt("Длина массива a = " + a.length);
for(int i = 0; i < a.length; i++) {
a[i] = new Integer(pRand(500));
prt("a[" + i + "] = " + a[i]);
}
}
static void prt(String s) {
System.out.println(s);
}
} ///:~
Здесь даже после вызова new
начинается создание массива:
Integer[] a = new Integer[pRand(20)];
Это всего лишь массив ссылок, и процесс инициализации завершается только тогда, когда вы создаёте новый объект Integer
и присваиваете ему ссылку:
a[i] = new Integer(pRand(500));
Если вы забудете создать объект, то получите ошибку времени выполнения при попытке считывания пустого элемента массива.
Рассмотрим состав объекта String
в печатающей строке. Вы можете видеть, что ссылка на объект Integer
автоматически преобразуется в строку, представляющую значение внутри объекта.Массив объектов также можно инициализировать списком значений, заключённых в фигурные скобки. Это можно сделать двумя способами; первый из которых допускался только в Java 1.0, второй (эквивалентный) — начиная с Java 1.1:```java
//: ArrayInit.java
// Инициализация массива
public class ArrayInit { public static void main(String[] args) { Integer[] a = { new Integer(1), new Integer(2), new Integer(3), };
// Только для Java 1.1:
Integer[] b = new Integer[] {
new Integer(1),
new Integer(2),
new Integer(3),
};
} } ///:~
Эта практика обычно полезна, но имеет ограничение, поскольку размер массива определяется во время компиляции. Последняя запятая в списке инициализации является необязательной (эта возможность делает более удобным обслуживание длинных списков). Инициализация массива второй формой (поддерживаемая с Java 1.1) предоставляет более удобный синтаксис для создания и вызова методов, что позволяет достичь эффекта, аналогичного «переменной аргументной последовательности» в C (обычно называемой просто «переменной аргументной последовательности»). Эти эффекты включают неизвестное количество аргументов и неизвестные типы (если так выбрано). Поскольку все классы конечного уровня наследуются от общего корневого класса `Object`, можно создать метод, который принимает массив объектов типа `Object` и вызывать его следующим образом:
```java
//: VarArgs.java
// Использование синтаксиса массива Java 1.1 для создания
// переменной аргументной последовательности
class A { int i; }
``````java
public class VarArgs {
static void f(Object[] x) {
for(int i = 0; i < x.length; i++)
System.out.println(x[i]);
}
public static void main(String[] args) {
f(new Object[] {
new Integer(47), new VarArgs(),
new Float(3.14), new Double(11.11) });
f(new Object[] {"один", "два", "три"});
f(new Object[] {new A(), new A(), new A()});
}
}
///:~
```На данном этапе мы можем выполнить ограниченное количество действий над этими неизвестными объектами, и этот программный код использует автоматическое преобразование `String` для выполнения полезных действий над каждым `Object`. В главе 11 (определение типа во время выполнения или RTTI) вы узнаете, как исследовать точные типы таких объектов, чтобы иметь возможность выполнять интересные действия над ними.
### 4.5.1 Многомерные массивы
Можно легко создавать многомерные массивы в Java:```java
//: MultiDimArray.java
// Создание многомерных массивов.
import java.util.*;
public class MultiDimArray {
static Random rand = new Random();
static int pRand(int mod) {
return Math.abs(rand.nextInt()) % mod + 1;
}
public static void main(String[] args) {
int[][] a1 = {
{1, 2, 3},
{4, 5, 6}
};
for (int i = 0; i < a1.length; i++)
for (int j = 0; j < a1[i].length; j++)
prt("a1[" + i + "][" + j + "] = " + a1[i][j]);
// трёхмерный массив с фиксированной длиной:
int[][][] a2 = new int[2][2][4];
for (int i = 0; i < a2.length; i++)
for (int j = 0; j < a2[i].length; j++)
for (int k = 0; k < a2[i][j].length; k++)
prt("a2[" + i + "][" + j + "][" + k + "] = " + a2[i][j][k]);
// трёхмерный массив с векторами различной длины:
int[][][] a3 = new int[pRand(7)][][];
for (int i = 0; i < a3.length; i++) {
a3[i] = new int[pRand(5)][];
for (int j = 0; j < a3[i].length; j++)
a3[i][j] = new int[pRand(5)];
}
for (int i = 0; i < a3.length; i++)
for (int j = 0; j < a3[i].length; j++)
for (int k = 0; k < a3[i][j].length; k++)
prt("a3[" + i + "][" + j + "][" + k + "] = " + a3[i][j][k]);
// массив объектов непростого типа:
Integer[][] a4 = {
{new Integer(1), new Integer(2)},
{new Integer(3), new Integer(4)},
{new Integer(5), new Integer(6)}
};
for (int i = 0; i < a4.length; i++)
for (int j = 0; j < a4[i].length; j++)
prt("a4[" + i + "][" + j + "] = " + a4[i][j]);
Integer[][] a5;
a5 = new Integer[3][];
for (int i = 0; i < a5.length; i++) {
a5[i] = new Integer[3];
for (int j = 0; j < a5[i].length; j++)
a5[i][j] = new Integer(i * j);
}
for (int i = 0; i < a5.length; i++)
for (int j = 0; j < a5[i].length; j++)
prt("a5[" + i + "][" + j + "] = " + a5[i][j]);
}
static void prt(String s) {
System.out.println(s);
}
}
///:~
``````Код для печати использует `length`, поэтому ему не требуется зависеть от фиксированного размера массива.
Первый пример демонстрирует многомерный массив базовых данных типов. Мы можем использовать фигурные скобки для определения границ каждого вектора внутри массива:``````
int[][] a1 = {
{ 1, 2, 3, },
{ 4, 5, 6, },
};
Каждая пара квадратных скобок перемещает нас на следующий уровень массива.
Второй пример показывает трехмерный массив, созданный с помощью new
. В этом случае весь массив сразу распределяется:
int[][][] a2 = new int[2][2][4];
``
Но третий пример демонстрирует, что каждый вектор, составляющий матрицу, может иметь произвольную длину:
int[][][] a3 = new int[pRand(7)][][]; for(int i = 0; i < a3.length; i++) { a3[i] = new int[pRand(5)][]; for(int j = 0; j < a3[i].length; j++) a3[i][j] = new int[pRand(5)]; } ``
Для первого массива, созданного с помощью new
, длина его первого элемента случайна, а длина остальных элементов неопределена. Второе использование new
внутри цикла for
заполняет элементы, но состояние третьего индекса остаётся неопределенным до использования третьего new
.
По результатам вывода можно заметить, что если значения не были явно указаны при инициализации, они автоматически будут установлены равными нулю.
Аналогичные выражения могут использоваться для работы с массивами объектов, отличных от базовых типов. Это видно из четвёртого примера, который демонстрирует возможность сбора нескольких выражений new
с помощью фигурных скобок:
Integer[][] a4 = {
{ new Integer(1), new Integer(2) },
{ new Integer(3), new Integer(4) },
{ new Integer(5), new Integer(6) },
};
Пятый пример показывает, как постепенно строится массив объектов, отличных от базовых типов:``` Integer[][] a5; a5 = new Integer[3][]; for(int i = 0; i < a5.length; i++) { a5[i] = new Integer[3]; for(int j = 0; j < a5[i].length; j++) a5[i][j] = new Integer(i * j); }
`i * j` просто устанавливает интересное значение в `Integer`.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )