ArrayList apples = new ArrayList(), forCint i = 0; i < 3; i++)

apples, add (new AppleO); // Ошибка компиляции: // apples.add(new OrangeO); for(int i = 0; i < apples.size(); i++)

System, out. pri ntl n(appl es. get( i) .idO). // Использование синтаксиса foreach: for(Apple с • apples)

System.out.pri nt1n(с.i d());

}

} /* Output: 0 1 2 0 1 2

*///-

На этот раз компилятор не разрешит поместить объекты Orange в контейнер apples, поэтому вы получите ошибку на стадии компиляции (а не на стадии выполнения).

Также обратите внимание на то, что выборка данных из List не требует преобразования типов. Поскольку контейнер знает тип хранящихся в нем элементов, он автоматически выполняет преобразование при вызове get(). Таким образом, параметризация не только позволяет компилятору проверять тип объектов, помещаемых в контейнеры, но и упрощает синтаксис работы с объектами в контейнере. Пример также показывает, что, если индексы элементов вам не нужны, для перебора можно воспользоваться синтаксисом foreach.

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

//: hoiding/GenericsAndUpcasting.java import java.util.*;

class GrannySmith extends Apple {}

class Gala extends Apple {}

class Fuji extends Apple {}

class Braeburn extends Apple {}

public class GenericsAndUpcasting {

public static void main(String[] args) {

ArrayList apples = new ArrayList();

apples.add(new GrannySmithO);

apples.add(new GalaO);

apples.add(new Fuji()):

apples.add(new BraeburnO);

for(Apple с : apples)

System.out.println(c);

}

} /* Output: (Sample) GrannySmi th@7d772e Gala@llb86e7 Fuji@35ce36 Braeburn@757aef *///:-

Мы видим, что в контейнер, рассчитанный на хранение объектов Apple, можно помещать объекты типов, производных от Apple.

В результатах, полученных с использованием метода toStringO объекта Object, выводится имя класса с беззнаковым шестнадцатеричным представлением хеш-кода объекта (сгенерированного методом hashCode()).

Основные концепции

В библиотеке контейнеров Java проблема хранения объектов делится на две концепции, выраженные в виде базовых интерфейсов библиотеки:

• Коллекция: группа отдельных элементов, сформированная по некоторым правилам. Класс List (список) хранит элементы в порядке вставки, в классе Set (множество) нельзя хранить повторяющиеся элементы, а класс Queue (очередь) выдает элементы в порядке, определяемом спецификой очереди (обычно это порядок вставки элементов в очередь).

• Карта: набор пар объектов «ключ-значение», с возможностью выборки по ключу. ArrayList позволяет искать объекты по порядковым номерам, поэтому в каком-то смысле он связывает числа с объектами. Класс Map (карта — также встречаются термины ассоциативный массив и словарь) позволяет искать объекты по другим объектам — например, получить объект значения по объекту ключа, по аналогии с поиском определения по слову.

Хотя на практике это не всегда возможно, в идеале весь программный код должен писаться в расчете на взаимодействие с этими интерфейсами, а точный тип указывается только в точке создания. Следовательно, объект List может быть создан так:

List apples = new ArrayList():

Обратите внимание на восходящее преобразование ArrayList к List, в отличие от предыдущих примеров. Если позднее вы решите изменить реализацию, достаточно сделать это в точке создания:

List apples = new LinkedList();

Итак, в типичной ситуации вы создаете объект реального класса, повышаете его до соответствующего интерфейса, а затем используете интерфейс во всем остальном коде.

Такой подход работает не всегда, потому что некоторые классы обладают дополнительной функциональностью. Например, LinkedList содержит дополнительные методы, не входящие в интерфейс List, а ТгееМар — методы, не входящие в Map. Если такие методы используются в программе, восходящее преобразование к обобщенному интерфейсу невозможно.

Интерфейс Collection представляет концепцию последовательности как способа хранения группы объектов. В следующем простом примере интерфейс Collection (представленный контейнером ArrayList) заполняется объектами Integer, с последующим выводом всех элементов полученного контейнера:

//: hoiding/SimpleCol1ection.java

import java.util .*;

public class SimpleCollection {

public static void main(String[] args) {

Collection с = new ArrayList(); for(int i = 0; i < 10; i++)

c.add(i); // Автоматическая упаковка for(Integer i : c)

System.out.print(i + ". ");

}

} /* Output:

0. 1. 2. 3. 4, 5. 6. 7, 8-. 9.

*///•-

Поскольку в этом примере используются только методы Collection, подойдет объект любого класса, производного от Collection, но ArrayList является самым простейшим типом последовательности.

Перейти на страницу:

Похожие книги