Содержание
| Предыдущая | СледующаяГЛАВА 10
В языке Ява массивы являются объектами (§4.3.1), которые создаются динамически, и могут иметь значение переменных типа Object (§4.3.2). Все методы класса Object могут быть вызваны массивом.
Объект массива содержит ряд переменных. Число переменных может быть нулевым, в случае когда массив, как говорят, является пустым. Переменные содержащиеся в массиве не имеют никаких имен; вместо этого ссылаются на массив с помощью выражений доступа, которые используют неотрицательные целые значения индекса. Эти переменные называются компонентами массива. Если массив имеет n компонент, мы говорим, что длина массива - n; При обращении к компонентам массива используют целочисленные индексы от 0 до n-1 включительно.
Все компоненты массива имеют одинаковый тип, который называется типом компонент массива. Если тип компонент массива - T, тогда массив пишется T [].
Тип компоненты массива может быть типом массив. Компоненты из такого массива могут содержать ссылки на подмассивы (т.е. на другие массивы). Если, начиная с какого-нибудь типа массив, рассматривать каждый компонент типа, и снова (если он - также является типом массив) компонент типа следующего типа, и так далее, в конечном счете должны достигнуть тип компоненты, который - не является типом массив; он называется типом элемента первоначального массива, и компоненты этого уровня структуры данных называются элементами первоначального массива.
Существует ситуация, в которой элемент массива может быть массивом: если тип элемента - Object, тогда некоторый, или все элементы могут быть массивами, потому что любой объект массива может быть присвоен любой переменной типа Object .
Тип массива пишется как имя типа элемента, сопровождаемого некоторым числом пустых пар квадратных скобок []. Число пар скобок указывает на глубину вложения массива. Длина массива - не является частью его типа.
Типом элемента массива может быть любой тип, примитивный или cсылка. В частности:
Типы массива используются в описаниях и в выражениях приведения (§15.15).
Переменная типа массив содержит ссылку на объект. Объявление переменной типа массив не создает массив объектов или не назначает какое-нибудь место для компонент массива. Оно создает только саму переменную, которая может содержать ссылку на массив. Однако, часть инициализатора оператора объявления (§8.3) может создавать массив, ссылка на который становится тогда начальным значением переменной.
Так как длина массива не является частью его типа, отдельная переменная типа массив может содержать ссылки на массивы различной длины.
Ниже приведены примеры объявления переменных массива, которые не создают массив:
int[] ai; //массив типа int short[][] as; // массив из массивов типа short Object[] ao, // массив типа Object otherAo; // массив типа Object short s, // скаляр short aas[][]; // массив из массивов типа short
Ниже приведены некоторые примеры объявления переменных массива, которые создают массив объектов:
Exception ae[] = new Exception[3];
Object aao[][] = new Exception[2][3];
int[] factorial = { 1, 1, 2, 6, 24, 120, 720, 5040 };
char ac[] = { 'n', 'o', 't', ' ', 'a', ' ',
'S
', 't', 'r', 'i', 'n', 'g' };
String[] aas = { "array", "of", "String", };
Скобки [] могут появляться как часть типа в начале описаний, или как часть описания для конкретной переменной, или в обоих случаях сразу, как в этом примере:
byte[] rowvector, colvector, matrix[];
Это объявление эквивалентно следующему:
byte rowvector[], colvector[], matrix[][];
Как только объект массива создан, его длина никогда не изменяется. Чтобы создать переменную-массив, ссылающуюся на массив другой длины, нужна ссылка на различные массивы, которая должна быть присвоена переменной.
Если переменная-массив v имеет тип A[], где A - ссылочный тип, v может содержать ссылку на экземпляр любого типа массив B [], при условии что B может быть присвоен A. Это может происходить в результате времени выполнения на позднем присваивании; см. §10.10 для обсуждения.
Массив создается выражением создания массива (§15.9) или инициализатором массива (§10.6).
Выражение создания массива определяет тип элемента, число уровней вложенных массивов, и длину массива, по крайней мере одного из уровней вложения. Длина массива доступна как конечный экземпляр переменной length.
Инициализатор массива создает массив и обеспечивает начальные значения для всех компонент (Это контраст по сравнению с Cи и Cи ++, где это возможно для инициализатора массива, определяющего начальные значения для некоторых но не всех компонент массива.)
К компоненту массива обращаются с помощью выражения доступа к массиву (§15.12) которое состоит из выражения, чье значение - ссылка на массив, сопровождаемая индексным выражением, заключенным в скобки [], как в A[i]. Индексация всех массивов начинается с 0. Массив длиной n может быть индексирован целыми от 0 до n-1.
Массивы должны быть индексированы значениями типа int; short, byte, или также в качестве значений индекса могут использоваться значения типа char, потому что они подвергаются одноместному числовому расширению (§5.6.1) и становятся значениями типа int (т.е. целые). Попытка доступа к компоненте массива с помощью индекса значение у которого типа long вызовет ошибку времени компиляции.
Все обращения к массиву проверяются во время исполнения; попытка использовать индекс, значение которого меньше нуля или больше чем длина массива вызывает генерацию IndexOutOfBoundsException.
Пример:
class Gauss { public static void main(String[] args) { int[] ia = new int[101]; for (int i = 0; i < ia.length; i++) ia[i] = i; int sum = 0; for (int i = 0; i < ia.length; i++) sum += ia[i]; System.out.println(sum); } }
который вывод:
5050
объявляет переменную ia, которая является переменной типа массив из целых (int), то есть int[]. Переменная ia - инициализируется, чтобы сослаться на вновь созданный объект массива, созданного выражением создающим массив (§15.9). Выражение создающее массив определяет что массив должен иметь 101 компоненту. Длина массива доступна для использования поля length, как показано в примере программы, заполняющей массив целыми значениями от 0 до 100, которая выводит на экран сумму этих значений.
Инициализаторы массивов могут быть
определены в описании, создавая массив и
присваивая некоторые начальные значения:
ArrayInitializer:
{
VariableInitializersopt ,
opt }
VariableInitializers:
VariableInitializer
VariableInitializers ,
VariableInitializer
Для большей ясности следующее повторяется из §8.3:
VariableInitializer:
Expression
ArrayInitializer
Инициализатор массива пишется как список выражений разделенных запятой, заключенный в фигурные скобки "{" и "}".
Длина построенного массива будет равняться числу выражений.
Каждое выражение определяет значение для одного компонента массива. Каждое выражение должно быть совместимо по присваиванию (§5.2) с типом компонент массива, или происходит ошибка времени компиляции.
Если компонент массива сам является массивом, то выражение определяющее компонент может само быть инициализатором массива; то есть инициализатор массива может быть вложен.
Последние точка с запятой могут появляться после последнего выражения в инициализаторе массива и игнорируется.
Как в примере:
class Test { public static void main(String[] args) { int ia[][] = { {1, 2}, null }; for (int i = 0; i < 2; i++) for (int j = 0; j < 2; j++) System.out.println(ia[i][j]); } }
который выводит:
1 2
до возникновения NullPointerException при попытке индексирования второго компонента массива ia, который равен null.
Члены массива следующее:
Массив таким образом имеет те же самые методы что и следующий класс
class A implements Cloneable { public final int length = X; public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException e) { throw new InternalError(e.getMessage()); } } }Каждые массив реализуется иньтерфейсом Cloneable. Эти массивы являются cloneable, как показано в тестирующей программе:
class Test { public static void main(String[] args) { int ia1[] = { 1, 2 }; int ia2[] = (int[])ia1.clone(); System.out.print((ia1 == ia2) + " "); ia1[1]++; System.out.println(ia2[1]); } }
Которая выводит:
false 2
и которая показывает что компоненты массивов, обозначенных через ia1 и ia2, являются различными переменными. (В некоторых ранних реализациях языка Ява этот пример сбивается при компиляции, потому что компилятор неверно полагал, что метод clone для массива может генерировать CloneNotSupportedException.)
Метод сlone многомерного массива создает только одномерный новый массив. Подмассивы оказываются общими, как показано в примере программы :
class Test { public static void main(String[] args) throws Throwable { int ia[][] = { { 1 , 2}, null }; int ja[][] = (int[][])ia.clone(); System.out.print((ia == ja) + " "); System.out.println(ia[0] == ja[0] && ia[1] == ja[1]); } }
Который выводит:
false true
и показывает, что массивы типа int[], которыми являются ia[0] и ja[0] - это один и тот же массив.
Каждый массив имеет связанный объект Class, разделяемый со всеми другими массивами, имеющими тот же самый тип компонент. Суперкласс типа-массива рассматривается как Object, что видно из следующего примера:
class Test { public static void main(String[] args) { int[] ia = new int[3]; System.out.println(ia.getClass()); System.out.println(ia.getClass().getSuperclass()); } }
который печатает:
class [I class java.lang.Object
где строка "[I" является сигнатурой типа время выполнения для объекта класса "массив с компонентами типа int" (§20.1.1).
В языке Ява, в отличие от Cи, массив типа char - не String (§20.12), и ни строка, ни массив типа char не заканчиваются ‘\u0000‘ (символом NUL).
Объект String языка Ява не меняется, то есть никогда не меняется его содержание, в то время как массив типа char имеет непостоянные элементы. Метод toCharArray в классе String, возвращает массив символов, содержащий одинаковую последовательность символов, такую как String. Класс StringBuffer реализует полезные методы для непостоянных массивов символов (§20.13).Если v переменная-массив имеет тип A [ ], где A - ссылочный тип, тогда v может содержать ссылку для реализации любого типа-массива B [ ], если разрешается B присваивать А.
Таким образом, пример:
class Point { int x, y; } class ColoredPoint extends Point { int color; }class Test { public static void main(String[] args) { ColoredPoint[] cpa = new ColoredPoint[10]; Point[] pa = cpa; System.out.println(pa[1] == null); try { pa[0] = new Point(); } catch (ArrayStoreException e) { System.out.println(e); } } }
выводит следующее:
true java.lang.ArrayStoreException
Здесь переменная pa имеет тип Point[], и переменная cpa имеет его ссылочное значение для объекта типа ColoredPoint[]. ColoredPoint может присваиваться Point; поэтому значение cpa может быть присвоено pa.
Например, ссылка на этот массив pa, при проверке является ли pa [1]- null, не будет заканчиваться ошибкой времени выполнения. Это происходит потому, что элемент массива типа ColoredPoint[] - есть ColoredPoint, а ColoredPoint может рассматриваться как Point, поскольку Point - это суперкласс ColoredPoint.
С другой стороны, присваивание массиву pa может заканчиваться ошибкой во время выполнения. Во время компиляции, присваивание элементу pa проверяется, чтобы удостовериться в том, что присвоенное значение - Point. Но когда pa содержит ссылку на массив типа ColoredPoint присваивание допустимо, только если тип присвоенного значения во время выполнения - тип ColoredPoint.
Во время выполнения Ява контролирует такую ситуацию, чтобы гарантировать что присваивание допустимо; если это не так, то генерируется ArrayStoreException . Более формально: присваивание элементу массива, чей тип - A [ ], где A- тип ссылки, проверяется во время выполнения, чтобы гарантировать что присвоенное значение может предназначаться для фактического типа элементов массива, где фактическим типом элементов может быть любой ссылочный тип, который можно присвоить к A.
Содержание
| Предыдущая | Следующая