Java: руководство для начинающих
Шрифт:
Равнозначными являются и приведенные ниже строки кода. char table[] [] = new char[3] [4]; char[][] table = new char [3] [4];
Альтернативный синтаксис объявления массива оказывается удобным в тех случаях, если требуется объявить несколько массивов одного типа. Например: int[] nums, nums2, nums3; // создать три массива
В этом объявлении создаются три переменные, ссылающиеся на массивы типа int. Тот же результат можно получить с помощью следующей строки кода: int nums[], nums2[], nums3[]; // создать три массива
Альтернативный синтаксис объявления массива оказывается удобным и в тех случаях, если в качестве типа, возвращаемого методом, требуется указать массив. Например: int[] someMeth { ...
В этой строке кода объявляется метод someMeth , возвращающий целочисленный массив.
Обе рассмотренные выше формы объявления массивов
Присваивание значения одной переменной ссылки на массив другой переменной, по существу, означает, что обе переменные ссылаются на один и тот же массив, и в этом отношении массивы ничем не отличаются от любых других объектов. Такое присваивание не приводит ни к созданию копии массива, ни к копированию содержимого одного массива в другой. В качестве примера рассмотрим следующую программу: // Присваивание ссылок на массивы, class AssignARef { public static void main(String args[]) { int i; int numsl[] = new int[10]; int nums2[] = new int[10]; for(i=0; i < 10; i++) nums1[i] = i; for(i=0; i < 10; i++) nums2[i] = -i; System.out.print("Here is numsl: "); for(i=0; i < 10; i++) System.out.print(numsl[i] + " "); System.out.println; System.out.print("Here is nums2: "); for(i=0; i < 10; i++) System.out.print(nums2[i] + " "); System.out.println; // присвоить ссылку на массив // Теперь переменные nums2 и numsl ссылаются //на один и тот же массив. nums2 = numsl; System.out.print("Here is nums2 after assignment: "); for(i=0; i < 10; i++) System.out.print(nums2[i] + " "); System.out.println ; // выполнить операции над массивом numsl // по ссылке на массив nums2. nums2[3] = 99; System.out.print("Here is numsl after change through nums2: "); for(i=0; i < 10; i++) System.out.print(numsl[i] + " "); System.out.println; } }
Выполнение этой программы дает следующий результат: Here is numsl: 0123456789 Here is nums2: 0 -1 -2 -3 -4 -5 -6 -7 -8 -9 Here is nums2 after assignment: 0123456789 Here is numsl after change through nums2: 012 99 456789
Нетрудно заметить, что в результате присваивания ссылки на массив numsl переменной nums 2 обе переменные ссылаются на один и тот же массив. Применение переменной экземпляра length
В связи с тем что массивы реализованы в виде объектов, в каждом массиве содержится переменная экземпляра length. Значением этой переменной является число элементов, которые может содержать массив. (Иными словами, в переменной length содержится размер массива.) Ниже приведен пример программы, демонстрирующий данное свойство массивов. // Использование переменной экземпляра length, class LengthDemo { public static void main(String args[]) { int list[] = new int[10]; int nums[] = { 1, 2, 3 }; int tablet][] = { // таблица со строками переменной длины {1, 2, 3}, { 4, 5 }, {6, 7, 8, 9} }; System.out.println("length of list is " + list.length); System.out.println("length of nums is " + nums.length); System.out.println("length of table is " + table.length); System.out.println("length of table[0] is " + table[0].length); System.out.println("length of table[l] is " + table[1].length); System.out.println("length of table[2] is " + table[2].length); System.out.println ; // использовать переменную length для инициализации списка // Переменная length служит для управления циклом for. for(int i=0; i < list.length; i++) list[i] = i * i; System.out.print("Here is list: "); for (int i=0; i < list.length; i++) System.out.print(list[i] + " "); System.out.println ; } }
Выполнение этой программы дает следующий результат: length of list is 10 length of nums is 3 length of table is 3 length of table[0] is 3 length of table[1] is 2 length of table[2] is 4 Here is list: 0 1 4 9 16 25 36 49 64 81
Обратите особое внимание, каким образом переменная length используется в двумерном массиве. Как пояснялось ранее, двумерный массив представляет собой массив массивов. Поэтому приведенное ниже выражение позволяет определить число массивов, содержащихся в массиве table, table.length
Число таких массивов равно 3. Для того чтобы получить длину отдельного массива, содержащегося в массиве table, потребуется выражение, аналогичное следующему: table[0].length
Это выражение возвращает длину первого массива.
Анализируя код класса LengthDemo, следует также заметить, что выражение list. length используется в цикле for для определения
требуемого количества итераций. Учитывая то, что у каждого подмассива своя длина, пользоваться таким выражением удобнее, чем отслеживать вручную размеры массивов. Но не следует забывать, что переменная length не имеет никакого отношения к количеству фактически используемых элементов массива. Она содержит лишь данные о том, сколько элементов может содержать массив.Использование переменной экземпляра length позволяет упростить многие алгоритмы. Так, в приведенном ниже примере программы эта переменная используется при копировании одного массива в другой и предотвращает возникновение при выполнении программы исключительной ситуации в связи с превышением границ массива. // Использование переменной length для копирования массивов, class АСору { public static void main(String args[]) { int i; int numsl[] = new int[10]; int nums2[] = new int[10]; for(i=0; i < numsl.length; i++) numsl[i] = i; // копировать массив numsl в массив nums2 // Переменная length служит для сравнения размеров массивов. if(nums2.length >= numsl.length) for(i =0; i < nums2.length; i++) nums2[i] = numsl[i]; for(i=0; i < nums2.length; i++) System.out.print(nums2[i] + " "); } }
В данном примере переменная экземпляра length помогает решить две важные задачи. Во-первых, позволяет убедиться в том, что размера целевого массива достаточно для хранения содержимого исходного массива. И во-вторых, с ее помощью формируется условие завершения цикла, в котором выполняется копирование массива. Конечно, в столь простом примере размеры массивов нетрудно отследить и без переменной экземпляра length, но подобный подход может быть применен для решения более сложных задач.
В данном примере переменная экземпляра length помогает решить две важные задачи. Во-первых, позволяет убедиться в том, что размера целевого массива достаточно для хранения содержимого исходного массива. И во-вторых, с ее помощью формируется условие завершения цикла, в котором выполняется копирование массива. Конечно, в столь простом примере размеры массивов нетрудно отследить и без переменной экземпляра length, но подобный подход может быть применен для решения более сложных задач.
Пример для опробования 5.2. Создание класса очереди
Вам, вероятно, известно, что структура данных — это способ их организации. Одной из самых простых структур является массив, который представляет собой линейный список элементов, допускающий произвольный доступ к ним. Нередко массивы используются в качестве основания для создания более сложных структур вроде стеков или очередей. Стек — это набор элементов с организацией доступа по принципу “первым пришел — последним обслужен”, А очередь — это набор элементов с организацией доступа по принципу “первым пришел — первым обслужен”. Стек можно сравнить со стопкой тарелок на столе: первая тарелка снизу стопки используется последней. А очередь можно сравнить с выстроившейся очередью к окошку в банке: клиент, стоящий в очереди первым, обслуживается первым.
В очередях и стеках нас больше всего интересует способ хранения информации и обращения к ней. И стеки, и очереди представляют собой механизмы доступа к данным, в которых хранение и извлечение информации поддерживается самой структурой, а не реализуется в программе. Такое сочетание способов хранения и обработки данных лучше всего реализуется в рамках класса, поэтому в данном проекте предстоит создать простой класс очереди.
В очереди поддерживаются две основные операции: размещение и извлечение. При выполнении операции размещения новый элемент помещается в конец очереди, а при операции извлечения очередной элемент извлекается из начала очереди. Операции с очередью являются истощающими: элемент, однажды извлеченный из очереди, не может быть извлечен из нее повторно. Очередь может быть переполнена, когда в ней не остается места для новых элементов. Но очередь может быть и пуста, когда в ней нет ни одного элемента.
И последнее замечание: существуют два типа очередей — циклические и нециклические. В циклической очереди элементы массива, на основе которого она создана, могут использоваться повторно по мере удаления данных. Нециклическая очередь не позволяет повторно использовать элементы, поэтому со временем пространство для хранения новых элементов исчерпывается. Нециклическую очередь создать намного проще, чем циклическую, поэтому именно ее мы и реализуем в данном примере для опробования. Но если немного подумать, то нециклическую очередь можно без особого труда превратить в циклическую.