Файл: Курс лекция по Java. Лекция 9.pdf

Добавлен: 05.02.2019

Просмотров: 1415

Скачиваний: 7

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
background image

Значение индекса массива всегда имеет тип int. При обращении к элементу можно также
использовать byte, short или char, поскольку эти типы автоматически расширяются до int.
Попытка использовать long приведет к ошибке компиляции.

Соответственно,  и  поле  length  имеет  тип  int,  а  теоретическая  максимально  возможная
длина массива равняется 2^31-1, то есть немногим больше 2 млрд.

Продолжая рассмотрение типа массива, подчеркнем, что в качестве базового типа может
использоваться любой тип Java, в том числе:

интерфейсы. В таком случае элементы массива могут иметь значение null или ссылаться
на объекты любого класса, реализующего этот интерфейс.

абстрактные классы. В этом случае элементы массива могут иметь значение null или
ссылаться на объекты любого неабстрактного класса-наследника.

Поскольку массив является объектным типом данных, его значения могут быть приведены
к типу Object или, что то же самое, быть присвоены переменной типа Object. Например,

 

Object o = new int[4]; 

Это дает интересную возможность для массивов, основанных на типе Object, хранить в
качестве элемента ссылку на самого себя:

 

Object arr[] = new Object[3];

arr[0]=new Object();

arr[1]=null;

arr[2]=arr; // Элемент ссылается на весь массив!  

2.2. Инициализация массивов

Теперь, когда понятно, как создавать экземпляры массива, рассмотрим, какие значения
принимают его элементы.

Если создать массив на основе примитивного числового типа, то изначально после создания
все элементы массива имеют значение по умолчанию, то есть 0. Если массив объявлен
на  основе  примитивного  типа  boolean,  то  и  в  этом  случае  все  элементы  будут  иметь
значение по умолчанию false. Выше рассматривался пример инициализации элементов с
помощью цикла for.

Рассмотрим создание массива на основе ссылочного типа. Предположим, это будет класс
Point. При создании экземпляра массива с применением ключевого слова new не создается
ни  один  объект  класса  Point,  создается  лишь  один  объект  массива.  Каждый  элемент
массива будет иметь пустое значение null. В этом можно убедится с помощью простого
примера:

 

Point p[]=new Point[5];

for (int i=0; i<p.length; i++) {

   System.out.pritnln(p[i]);

Результатом будут лишь слова null.

Программирование на Java

Стр. 4 из 21

Массивы, как тип данных в Java

Rendered by 

www.RenderX.com


background image

Далее нужно инициализировать элементы массива по отдельности, например, в цикле.
Вообще, создание массива длиной n можно рассматривать как заведение n переменных,
и  работать  с  элементами  массива  (в  последнем  примере  p[i])  по  правилам  обычных
переменных.

Кроме  того,  есть  и  другой  способ  создания  массивов  -  инициализаторы.  В  этом  случае
ключевое слово new не используется, а ставятся фигурные скобки, и в них перечисляются
через запятую значения всех элементов массива. Например, для числового массива явная
инициализация записывается следующим образом:

 

int i[]={1, 3, 5};

int j[]={}; // эквивалентно new int[0] 

Длина массива вычисляется автоматически, исходя из количества введенных значений.
Далее создается массив такой длины, и каждому его элементу присваивается указанное
значение.

Аналогично можно порождать массивы на основе объектных типов, например:

 

Point p=new Point(1,3);

Point arr[]={p, new Point(2,2), null, p};

// или

String sarr[]={"aaa", "bbb", "cde"+"xyz"}; 

Однако инициализатор нельзя использовать для анонимного создания экземпляров массива,
то есть не для инициализации переменной, а, например, для передачи параметров метода
или конструктора.

Например:

 

public class Parent {

   private String[] values;

   protected Parent(String[] s) {

      values=s;

   }

}

public class Child extends Parent {

   public Child(String firstName, String lastName) {

      super(???); // требуется анонимное создание массива

   }

В конструкторе класса Child необходимо сделать обращение к конструктору родителя и
передать в качестве параметра ссылку на массив. Теоретически можно передать null, но
это  приведет  в  большинстве  случаев  к  некорректной  работе  классов.  Можно  вставить
выражение new String[2], но тогда вместо значений firstName и lastName будут переданы
пустые строки. Попытка записать {firstName, lastName} приведет к ошибке компиляции, так
можно только инициализировать переменные.

Инициализация массивов

Стр. 5 из 21

Программирование на Java

Rendered by 

www.RenderX.com


background image

Правильное выражение выглядит так:

 

new String[]{firstName, lastName} 

Что  является  некоторой  смесью  выражения,  создающего  массивы  с  помощью  new  и
инициализатора. Длина массива определяется количеством указанных значений.

2.3. Многомерные массивы

Теперь  перейдем  к  рассмотрению  многомерных  массивов.  Например,  в  следующем
примере:

 

int i[][]=new int[3][5]; 

переменная i ссылается на двумерный массив, который можно представить себе в виде
таблицы  3х5.  Суммарно  в  таком  массиве  содержится  15  элементов,  к  которым  можно
обращаться через комбинацию индексов от (0, 0) до (2, 4). Пример заполнения двумерного
массива через цикл:

 

int pithagor_table[][]=new int[5][5];

for (int i=0; i<5; i++) {

   for (int j=0; j<5; j++) {

      pithagor_table[i][j]=i*j;

      System.out.print(pithagor_table[i][j]+ "\t");

   }

   System.out.println();

Результатом выполнения программы будет:

 

0   0   0   0   0   

0   1   2   3   4   

0   2   4   6   8   

0   3   6   9   12   

0   4   8   12   16    

Однако, такой взгляд на двумерные и многомерные массивы является неполным. Более
точный  подход  заключается  в  том,  что  в  Java  нет  двумерных,  и  вообще  многомерных,
массивов, а есть массивы, базовыми типами которых являются также массивы. Например,
тип int[] означает "массив чисел", а int[][] означает "массив массивов чисел". Поясним такую
точку зрения следующими подробностями.

Если создать двумерный массив и определить переменную x, которая на него ссылается,
то используя x и два числа в паре квадратных скобок каждое (например, x[0][0]), можно
обратиться к любому элементу двумерного массива. Но в то же время используя x и одно
число  в  паре  квадратных  скобок,  можно  обратиться  к  одномерному  массиву,  который
является элементом двумерного массива. Его можно проинициализировать новым массивом
с  некоторой  другой  длиной,  и  таблица  перестанет  быть  прямоугольной  -  она  примет
произвольную  форму.  В  частности,  можно  одному  из  одномерных  массивов  присвоить
даже значение null.

Программирование на Java

Стр. 6 из 21

Массивы, как тип данных в Java

Rendered by 

www.RenderX.com


background image

 

int x[][]=new int[3][5]; // прямоугольная таблица

x[0]=new int[7];

x[1]=new int[0];

x[2]=null; 

После таких операций массив, на который ссылается переменная x назвать прямоугольным
никак нельзя. Зато хорошо видно, что это просто набор одномерных массивов или значений
null.

Полезно подсчитать, сколько объектов порождается выражением new int[3][5]. Правильный
подсчет  таков:  создается  один  массив  массивов  (1  объект)  и  3  массива  чисел,  каждый
длиной 5 (3 объекта). Итого, 4 объекта.

В рассмотренном примере 3 из них (массивы чисел) были тут же переопределены новыми
значениями.  Для  таких  случаев  полезно  использовать  упрощенную  форму  выражения
создания массивов:

 

int x[][]=new int[3][];

 

Такая запись порождает один объект - массив массивов, и заполняет его значениями null.
Теперь понятно, что и в этом, и в предыдущем варианте выражение x.length возвращает
значение 3 - длину массива массивов. Далее можно с помощью выражений x[i].length узнать
длину каждого вложенного массива чисел при условии, что i неотрицательно и меньше
x.length, а также x[i] не равно null. Иначе будут возникать ошибки во время выполнения
программы.

Вообще при создании многомерных массивов с помощью new необходимо указывать все
пары  квадратных  скобок,  соответственно  количеству  измерений.  Но  заполненной
обязательно  должна  быть  лишь  самая  левая  пара,  это  значение  задаст  длину  самого
верхнего массива массивов. Если заполнить следующую пару, то этот массив заполнится
не значениями по умолчанию null, а новыми созданными массивами с меньшей на единицу
размерностью.  Если  заполнена  вторая  пара  скобок,  то  можно  заполнить  третью  и  так
далее.

Аналогично, для создания многомерных массивов можно использовать инициализаторы.
В этом случае используется столько вложенных фигурных скобок, сколько требуется:

 

int i[][] = {{1,2}, null, {3}, {}}; 

В этом примере порождается 4 объекта. Это, во-первых, массив массивов длиной 4, а во-
вторых, 3 массива чисел с длинами 2, 1, 0 соответственно.

Все рассмотренные примеры и утверждения одинаково верны для многомерных массивов,
основанных как на примитивных, так и на ссылочных типах.

2.4. Класс массива

Поскольку массив является объектным типом данных, то можно попытаться представить
себе, как бы выглядело объявление класса такого типа. На самом деле эти объявления
не хранятся в файлах или еще каком-нибудь формате. Учитывая, что массив может быть

Класс массива

Стр. 7 из 21

Программирование на Java

Rendered by 

www.RenderX.com


background image

объявлен  на  основе  любого  типа  и  иметь  произвольную  размерность,  это  физически
невыполнимо,  да  и  не  требуется.  Вместо  этого  во  время  выполнения  приложения
виртуальная машина генерирует их динамически на основе базового типа и размерности,
и затем они хранятся в памяти в виде таких же экземпляров класса Class, как и для любых
других типов.

Рассмотрим  гипотетическое  объявление  класса  для  массива,  основанного  на  неком
объектном типе Element.

Объявление класса начинается с перечисления модификаторов, среди которых особую
роль  занимают  модификаторы  доступа.  Класс  массива  будет  иметь  такой  же  уровень
доступа, как и базовый тип. Т.е., если Element объявлен как public-класс, то и массив будет
иметь уровень доступа public. Для любого примитивного типа класс массива будет public.
Можно также указать модификатор final, поскольку никакой класс не может наследоваться
от класса массива.

После этого идет имя класса, на котором можно подробно не останавливаться, т.к. к типу
массиву обращение идет не по его имени, а по имени базового типа и набору квадратных
скобок.

Затем нужно указать родительский класса. Все массивы наследуются напрямую от класса
Object.  Далее  перечисляются  интерфейсы,  которые  реализует  класс.  Для  массива  это
будут интерфейсы Cloneable и Serializable. Первый из них подробно рассматривается в
конце этой главы, а второй будет рассмотрен в следующих главах.

Тело  класса  содержит  объявление  одного  public  final  поля  length  типа  int.  Кроме  того
переопределен метод clone() для поддержки интерфейса Cloneable.

Сведем все вышесказанное в формальную запись класса:

 

[public] class A implements Cloneable, java.io.Serializable {

   public final int length; // инициализируется при создании

   public Object clone() {

      try {

         return super.clone();

      } catch (CloneNotSupportedException e) {

         throw new InternalError(e.getMessage());

      }

   }

Таким  образом,  тип  массивы  является  полноценным  объектом,  который,  в  частности,
наследует все методы, определенные в классе Object, например, toString(), hashCode() и
остальные.

Например:

 

// результат работы метода toString()

System.out.println(new int[3]);

System.out.println(new int[3][5]);

System.out.println(new String[2]);

Программирование на Java

Стр. 8 из 21

Массивы, как тип данных в Java

Rendered by 

www.RenderX.com