русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

Параметризованные и типизованные контейнеры


Дата добавления: 2015-06-12; просмотров: 949; Нарушение авторских прав


Одна из проблем, существовавших при работе с контейнерами до выхода Java SE5, заключалась в том, что компилятор позволял вставить в контейнер объект неверного типа. Для примера рассмотрим один из основных рабочих контейнеров ArrayList, в котором мы собираемся хранить объекты Apple. Пока рассматривайте ArrayList как «автоматически расширяемый массив». Работать с ним несложно: создайте объект, вставляйте объекты методом add(), обращайтеcь к ним методом get(), используйте индексирование — так же, как для массивов, но без квадратных скобок. ArrayList также содержит метод size(), который возвращает текущее количество элементов в массиве. В следующем примере в контейнере размещаются объекты Apple и Orange, которые затем извлекаются из него. Обычно компилятор Java выдает предупреждение, потому что в данном примере не используется параметризация, однако в Java SE5 существует специальная директива @SuppressWarnings для подавления предупреждений. Директивы начинаются со знака @ и могут получать аргументы; в данном случае аргумент означает, что подавляются только «непроверяемые» предупреждения:

//: holding/ApplesAndOrangesWithoutGenerics.java

// Простой пример работы с контейнером

// (компилятор выдает предупреждения).

import java.util.*;

 

class Apple {

private static long counter;

private final long id = counter++;

public long id() { return id; }

}

 

class Orange {}

 

public class ApplesAndOrangesWithoutGenerics {

@SuppressWarnings("unchecked")

public static void main(String[] args) {

ArrayList apples = new ArrayList();

for(int i = 0; i < 3; i++)

apples.add(new Apple());

// He препятствует добавлению объекта Orange:

apples.add(new Orange());

for(int i = 0; i < apples.size(); i++)

((Apple)apples.get(i)).id();



// Объект Orange обнаруживается только во время выполнения

}

}

Директивы Java SE5 будут рассмотрены позднее. Apple и Orange — совершенно разные классы; они не имеют ничего общего, кроме происхождения от Object (напомню: если в программе явно не указан базовый класс, то в этом качестве используется Object). Так как вArrayList хранятся объекты Object, метод add() может добавлять в контейнер не только объекты Apple, но и Orange, без ошибок компиляции или времени выполнения. Но при вызове метода get() класса ArrayList вы вместо объекта Apple получаете ссылку на Object, которую необходимо преобразовать в Apple. Все выражение должно быть заключено в круглые скобки, чтобы преобразование было выполнено перед вызовом метода id() класса Apple. Во время выполнения, при попытке преобразования объекта Orange в Apple, произойдет исключение. В главе «параметризованные типы» вы узнаете, что создание классов, использующих механизм параметризации, может быть довольно сложной задачей. С другой стороны, с применением готовых параметризованных классов проблем обычно не бывает. Например, чтобы определить объект ArrayList, предназначенный для хранения объектов Apple, достаточно использовать вместо имени ArrayList запись АrrayList< Apple>. В угловых скобках перечисляются параметры типов (их может быть несколько), указывающие тип объектов, хранящихся в данном экземпляре контейнера. Механизм параметризации предотвращает занесение объектов неверного типа в контейнер на стадии компиляции. Рассмотрим тот же пример, но с использованием параметризации:

//: holding/ApplesAndOrangesWithGenerics.java

import java.util.*;

 

public class ApplesAndOrangesWithGenerics {

public static void main(String[] args) {

ArrayList<Apple> apples = new ArrayList<Apple>();

for(int i = 0; i < 3; i++)

apples.add(new Apple());

// Ошибка компиляции:

// apples.add(new Orange());

for(int i = 0; i < apples.size(); i++)

System.out.println(apples.get(i).id());

// Использование foreach:

for(Apple c : apples)

System.out.print(c.id() + " ");

}

}

<spoiler text="Output:">

0 1 2 0 1 2

</spoiler> На этот раз компилятор не разрешит поместить объекты Orange в контейнер apples, поэтому вы получите ошибку на стадии компиляции (а не на стадии выполнения). Также обратите внимание на то, что выборка данных из List не требует преобразования типов. Поскольку контейнер знает тип хранящихся в нем элементов, он автоматически выполняет преобразование при вызове get(). Таким образом, параметризация не только позволяет компилятору проверять тип объектов, помещаемых в контейнеры, но и упрощает синтаксис работы с объектами в контейнере. Пример также показывает, что, если индексы элементов вам не нужны, для перебора можно воспользоваться синтаксисом foreach. Вы не обязаны точно соблюдать тип объекта, указанный в качестве параметра типа. Восходящее преобразование работает с параметризованными контейнерами точно так же, как и с другими типами:

//: holding/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<Apple> apples = new ArrayList<Apple>();

apples.add(new GrannySmith());

apples.add(new Gala());

apples.add(new Fuji());

apples.add(new Braeburn());

for(Apple c : apples)

System.out.println(c);

}

}

<spoiler text="Output:"> (Sample)

GrannySmith@7d772e

Gala@11b86e7

Fuji@35ce36

Braeburn@757aef

</spoiler> Мы видим, что в контейнер, рассчитанный на хранение объектов Apple, можно помещать объекты типов, производных от Apple. В результатах, полученных с использованием метода toString() объекта Object, выводится имя класса с беззнаковым шестнадцатеричным представлением хеш-кода объекта (сгенерированного методом hashCode()).

 



<== предыдущая лекция | следующая лекция ==>
Глава 11 КОНТЕЙНЕРЫ И ХРАНЕНИЕ ОБЪЕКТОВ | Основные концепции


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 0.07 сек.