Родовые классы в языке Java
? Любое извлечение объекта из коллекции должно сопровождаться явным приведением объекта к соответствующему типу.
? Возможно добавление в коллекцию любого элемента, даже если коллекция предназначена для объектов только класса Integer.
? Любые коллекции не могут содержать величины примитивных типов. Перед сохранением в ArrayList целую величину нужно положить в экземпляр класса Integer.
Например, рассмотрим следующий фрагмент:
//* Создать объект класса ArrayList ArrayList theArray = new ArrayList();
//* Создать элемент theArray.add(0, new Integer(72));
//* Получить первый объект
Integer theInt = (Integer) theArray.get(0);
В настоящее время классы коллекций, среди которых наиболее популярным считают ArrayList, могут стать родовыми классами.
Такие классы конкретизируются вызовом конструктора new и передачей ему родового параметра, заключенного в угловые скобки. К примеру, класс ArrayList можно конкретизировать для сохранения объектов класса Integer и получить конкретный объект:ArrayList theArray = new ArrayList ();
Этот новый класс снимает две проблемы коллекций. В коллекцию theArray можно положить только объекты класса Integer. Более того, при извлечении объекта из коллекции не требуется его явное приведение.
Язык Java также включает интерфейсы для таких коллекций, как списки, очереди и множества.
Пользователи могут определять свои собственные родовые классы. Например, мы можем записать: public class TheClass {}
Данный класс можно конкретизировать и создать соответствующий объект следующим образом:
TheClass theString;
У подобных пользовательских родовых классов есть определенные недостатки:
? они не могут хранить примитивные величины;
? элементы не могут индексироваться. Элементы должны добавляться к коллекциям методом add.
Параметрический полиморфизм в АТД |
421 |
Давайте реализуем родовой стек на основе коллекции ArrayList: import java.util.*; public class NewStack { private ArrayList refStack; private int maxLen; public NewStack() { // A constructor refStack = new ArrayList (); maxLen = 499; } public void push(T newValue) { if (refStack.size() == maxLen) System.out.println(''Error in push-stack is full"); else refStack.add(newValue); } public void pop() { if (refStack.isEmpty()); System.out.println(''Error in pop-stack is empty"); else refStack.remove(refStack.size() - 1); } public T top() { return (refStack.get(refStack.size() - 1)); } public boolean empty() {return (refStack.isEmpty()); } Здесь последний элемент в ArrayList находится с помощью метода size, который возвращает количество элементов в структуре. Элементы удаляются из структуры при помощи метода remove. Рассматриваемый класс может быть конкретизирован для типа String (с построением соответствующего объекта) следующим образом: NewStack theStack = new NewStack (); Как упоминалось в главе 13, в языке поддерживаются подстановочные классы. Например, Collection является подстановочным классом для всех классов коллекций. Это позволяет написать метод, который в качестве типа параметра может использовать любой тип коллекции. Поскольку коллекция сама по себе является родовой, класс Collection можно считать родовым для родового класса. При работе с объектами подстановочного типа следует соблюдать предельную осторожность. Поскольку компоненты конкретного объекта этого типа имеют свой тип, объекты других типов уже не смогут добавляться в коллекцию. Приведем пример: Collection strColln = new ArrayList(); Фактически, здесь запрещается добавление в коллекцию объектов, не имеющих типа String. Достаточно просто определить родовой класс для работы только с ограниченным набором типов. Например, класс может объявлять переменную родового типа и вызывать с ее помощью метод compareTo. При попытке конкретизации такого класса для типа, который не имеет метода compareTo, должна фиксироваться ошибка. Для предотвращения возможности конкретизации родового |
422 |
Глава 15. Абстрактные типы данных |
класса типом, не поддерживающим метод compareTo, нужно задать следующий родовой параметр: В языке Java Comparable является интерфейсом, в котором объявлен метод compareTo. Если в определении класса будет записан этот родовой тип, то вводится запрет на конкретизацию любым типом, не реализующим Comparable. Использование зарезервированного слова extends в данном контексте выглядит, по меньшей мере, странно, очевидно разработчики намекали на ассоциацию с понятием подтипа. |