Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Дженерики (Часть 2); Версия 3.docx
Скачиваний:
4
Добавлен:
17.03.2016
Размер:
1.42 Mб
Скачать

Жёлтым я пометил новые фрагменты.

Добавлена дерево запретов.

Исправлено больше ошибок.

Дженерики. Часть 3.

Дзюба Влад. ИП-42

Болше о шаблонах аргументов Наследование в дженериках

Замечание: Любой код, который будет показан лучше всего вручную написать и проверить правильность утверждений (ведь это круто – найти ошибку в лекции ). Также это помогает забить в пальцы и глаза синтаксис языка.

Рассмотрим такой код:

Этот код вызывает функцию someMethod два раза: первый раз с Integer, второй с Double, хотя при объявлении задано, что функция принимает агрумент типа Number. Это возможно благодаря тому, что Integer и Double являются подклассами Number.

Теперь перейдём к нашей теме дженериков:

Во-первых, какие елементы будут в списках после циклов?

Ну а теперь, обратим внимание на то, что компилятор выдаст ошибку при вызове someMethod в обоих случаях. На первый взгляд кажется, что, как и в предыдущем примере передавать вместо ArrayList<Number> можно передавать ArrayList<Integer> и ArrayList<Double>, но это не так!

Хотя Integer иDouble наследуются от Number, ArrayList<Integer>, ArrayList<Double> и ArrayList<Number> наследуются от Object.

Поэтому нужно использовать «?» для написания функции:

Посмотрите: мы изменили только тип аргумента функции и всё заработало. Теперь можно использовать любой подкласс Number для этой функции. В этом и состоит сила дженериков.

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

Также для создания дженериков я использовал алмазный синтаксис (diamond syntax), который позволяет не указывать параметризуемый тип второй раз

ArrayList<Integer> = new ArrayList<>();

Получается, что Integer и Double являются подклассами ? extends Number. Но также они являются подклассами ? extends Integer и ? extends Double соответственно. А ? extends Number является подклассом ? extends Object. Всё это можно представить в такой диагарамме.

Такую же диаграмму можно сделать и для классов, ограниченных словом super ? super Type используется для надклассов Type (Integer, Number и Object подходят под шаблон ? super Integer).

Это всё описывает наследование в пределах одного класса, но с разнымим параметризоваными типами.

Но допустим перед нами стоит задача: реализовать функцию, которая в любой коллекции чисел (Collection<Number>) ищет число 42. Почему 42? Потому что для этого и создают компьютеры . (http://lurkmore.to/42).

Сразу встаёт вопрос: как работать с любой коллекцией? Ведь коллекцией может быть, как и ArrayList, так и HashSet, так и LinkedList.

Это позволит сделать наследенование дженериков:

Наследование дженериков с одним параметризованым типом есть только, если этот тип одинаковый. То есть ниList<Integer>, ни List<String> не могут наследовать List<Number>.

Также будем использовать Iterator – это класс, позволяющий перебрать все элементы коллекции.

Вот пример функции, которая возвращает есть ли в коллекции 42.

(Для того, чтоб код скомпилировался нужно подключить java.util.Iterator, java.util.Collection)

Iterator itr = col.iterator();

Создаёт новый итератор и присвает ему итератор коллекции, передаваемой в функцию.

while (itr.hasNext())

Запускает цикл, который выполняется, пока в коллекции есть ещё необработаные элементы.

Number elem = (Number) itr.next();

Получает следующий элемент в коллекции. Так как тип коллекции –Collection<? Extends Number>, то мы по-любому имеем дело с Number и никаких ошибок, связаных с кастом (приведением типов) не будет.

Ну и находим числа, дробное представление которых равно 42.0. Что было бы, если бы внутри if было бы такое выражение: (elem.intValue() == 42)?

Функция готова, но теперь нужно её протестировать. Для того, чтобы видеть, что в данный момент находится в коллекции напишем функцию print, которая будет выводить все элементы любой коллекции.

(Для того, чтобы код скомпилился нужно вначале подключить java.util.Iteartor, java.util.Collection)

Во первых, функция принимает любую коллекцию: как Collection<Number>, так и LinkedHashSet<String>, так как тип аргумента Collection<?>

Интересно выражение:

col.getClass().getSimpleName()

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

Также для удобства создадим функцию, которая будет заносить какие-то элементы в коллекцию.

(Для того, чтобы код скомпилился нужно вначале подключить java.util.Collection)

Аргументом может быть коллекция любого надкласса Integer, потому что числа, которые мы заносим Integer и могут содержаться в любой такой коллекции.

Теперь работа с нашими функциями:

(Для того, чтобы код скомпилился нужно вначале подключить java.util.ArrayList, java.util.HashSet)

Для примера используем ArrayList<Integer> и HashSet<Number>. Для каждого добавляем элементы, выводим и анализируем есть ли 42 внутри. Каким должно быть возвращаемое из isWorldSolutionHere() значение, чтобы выводилось not?

В итоге в этом примере используется наследование дженерикиов, шаблоны «?» и методы Collection(iterator(), add()) и Object(toString()) для того, чтобы организовать методы, которые будут работать с любыми подходящими коллекциями. Внимание: это очень круто!

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