Похожие презентации:
Модуль_4_Тема_1
1. Модуль 4. Дженерики и коллекции в Java. Тема 4.1 Дженерики
Кнапп ИванJava разработчик в компании «Альфа-Капитал»
2.
Структура презентации1.
Введение
2.
Дженерики
3.
Где можно применять дженерики?
4.
Ограничения типизаций
5.
Итоги
6.
Практика
2
3.
Введение3
4.
ЗадачаЗадача, необходимо реализовать класс Pair, содержащий ключ key типа String
и его значение value типа String.
Pair
String key
String value
Не трудная задача правда. Класс Pair готов.
Теперь можно создать экземпляр класса Pair, передав в конструктор ключ и
значение:
4
5.
Новые вводные по задачеА что, если потребуется создать класс Pair, который также будет хранить ключ
key типа String, но при этом в качестве значения value хранить число типа
Integer?
Легко. Реализуем класс PairInteger, а наш прошлый класс переименуем в
PairString.
PairInteger
PairString
String
key
String
key
String
value
Integer
value
Задачу решили конечно, но есть одно но…
5
6.
Опять изменения. Как быть?А если нам понадобится класс для типов Time, Long и еще 100 других?
Неужели мы будем создавать новый Pair для каждого типа
Можно создать общий класс PairCommon и использовать его для хранения
любого типа:
Теперь мы можем
хранить любой тип,
но какая новая
проблема у нас
появилась ?
6
7.
Опять изменения. Как быть?Проблема нашего нового класса PairCommon в том, что метод getValue()
возвращает тип Object и, чтобы использовать значение, нужно каждый раз явно
приводить тип:
Выяснить, какого типа объект мы положили в наш класс типа PairCommon на
этапе компиляции, нет никакой возможности (кроме как визуально изучить код).
Вопрос: а что будет, если мы ошибемся с типом и попробуем положить тип LocalTime, а
прочитать его как тип Integer?
7
8.
Опять изменения. Как быть?На этапе компиляции никакую ошибку мы не получим, а вот во время работы
программы, да:
Exception in thread "main" java.lang.ClassCastException: class java.time.LocalTime
cannot be cast to class java.lang.Integer
Давайте вернемся к идее создания отдельных классов PairCommon для каждого
типа, таких как Boolean, Integer, String и Double. Этот метод обеспечивает
безопасность во время выполнения программы, но требует создания новых
классов PairSomething и дублирования кода для каждого нового типа.
Это приводит к избыточности кода
Гарантирует безопасное выполнение
Это кажется хорошим решением, но...
8
9.
Опять изменения. Как быть?Конечно НЕТ! Это превратит наш код в беспорядок. Избежим дублирования
кода!
В этом помогут обобщения или generics или просто дженерики. С их помощью
можно указать тип данных, который будет храниться в классе Pair при создании
его экземпляра.
И для этого потребуется всего один класс Pair.
До дженериков:
PairString
С использование дженериков:
Pair<T>
PairInteger
PairDouble
9
10.
Дженерики10
11.
ОпределениеОбобщения (generics) — это средство в языке Java, предназначенное для
реализации обобщённого программирования.
Они позволяют работать с разными типами данных в одних и тех же методах
и классах без изменения их описания.
Они обеспечивают более строгую проверку типов на этапе компиляции и
устраняют необходимость в явном приведении типов.
Дженерики легко идентифицировать по наличию указателя типа <T>(буква не
имеет значения), будь то класс, метод или конструктор.
11
12.
Красивое решениеПерепишем наш класс Pair с использованием новых знаний о дженериках
Pair<T>
String key
T value
Теперь можно переиспользовать класс Pair гораздо эффективнее:
12
13.
Создание класса с параметромКласс Pair позволяет легко создавать
новые объекты и хранить в поле value
значения любого типа, при условии,
что этот тип соответствует параметру T
класса Pair.
Типизированные классы особенно
полезны в таких случаях.
Для метода getValue мы указали T в
качестве типа возвращаемого
значения, поскольку на этапе описания
метода этот тип является обобщенным
и неизвестным.
13
14.
Создание экземпляра классаПри создании экземпляра класса Pair необходимо указать конкретный
тип, который заменит типизированный параметр, поместив его в
угловые скобки после имени класса.
Например, если первый объект будет использовать тип Integer, то
вместо T будет подставлен Integer:
А второй объект будет типа LocalTime
14
15.
Внимание ограниченияДля указания типа в дженериках применяются исключительно классы, а
примитивные типы использовать нельзя. Поэтому такие типы как int, double,
boolean и другие, использовать не допускается.
Вместо них следует применять их классы-обертки:
Integer вместо int,
Double вместо double,
Boolean вместо boolean,
и т.д.
Как пример, Pair<Double> или Pair<Boolean> .
15
16.
Алмазный синтаксисЧтобы избежать указания типов вручную, в Java 7 был предложен алмазный
синтаксис. Этот синтаксис позволяет пропустить параметры типа,
предоставляя компилятору возможность самостоятельно определить типы при
создании объекта.
Пример упрощенного объявления:
Алмазный синтаксис тесно связан с концепцией вывода типов. Когда
компилятор обнаруживает <> справа, он обращает внимание на левую часть,
где указано объявление типа переменной, которой присваивается значение.
Таким образом, он определяет, какой тип следует использовать справа.
Еще пример короткой записи:
16
17.
Конструкции использования<generics> или
где их можно применять ?
17
18.
Где можно применить дженерики?Ответ:
Классах
Конструкторах
Методах
Интерфейсах
18
19.
Типизированный конструкторКонструкторы, подобно классам, могут быть обобщёнными. В такой ситуации
перед конструктором в угловых скобках указываются параметры типов.
Теперь мы можем создать
экземпляр класса Pair, передавая
любой объект в качестве value, и
он будет преобразован в String.
19
20.
Типизированный методМетоды, которые взаимодействуют с разными типами параметров, называются
типизированными.
Они позволяют использовать одну и ту же функциональность с различными
типами объектов, такими как String, Long, Boolean и другие.
Типизированные методы можно легко распознать по наличию указателя типа
<T>.
Пример статичного метода:
20
21.
Типизированный интерфейсИнтерфейсы, подобно классам, могут быть параметризованны типами.
При реализации типизированного интерфейса можно
использовать два подхода:
1. Задать типизированный параметр интерфейса конкретным типом. В
этом случае класс, реализующий интерфейс, будет жестко связан с
данным типом.
2. Класс использует тот же типовой параметр, что и интерфейс,
сохраняя гибкость при реализации.
21
22.
Создание типизированного интерфейсаСоздадим типизированный интерфейс Pair:
Создание интерфейса аналогично созданию класса тип <T>
указывается в том же месте после названия интерфейса.
22
23.
Реализация типизированного интерфейсаСпособ 1.
В этом случае типизированный
параметр интерфейса Pair
устанавливается как конкретный
тип Double.
Таким образом, класс
SimplePair, реализующий
интерфейс Pair, становится
строго связанным с типом
Double.
23
24.
Реализация типизированного интерфейсаСпособ 2.
В данном подходе
типизированный параметр
интерфейса Pair передается
непосредственно в класс
SimplePair.
Таким образом, класс
SimplePair, реализующий
интерфейс Pair, также
становится типизированным.
24
25.
А если надо типизировать несколькопараметров, как быть ?
25
26.
Пример множественной типизацииРассмотрим множественную типизацию на примере обобщённого класса.
Можно одновременно задать несколько типовых параметров:
В этом случае, чтобы создать
экземпляр класса,
нужно сразу задать два параметра
String, Double:
26
27.
ВниманиеВажно отменить две вещи:
1) Кол-во параметров в обобщении может быть множество, но на практике их
не больше двух или трех
2) Выбор буквы, описывающий тип, ни на что не влияет
27
28.
Ограничения типизаций28
29.
ПрименениеПо умолчанию, классы можно параметризовать любым типом.
Однако иногда требуется, чтобы параметр принадлежал только определённому
набору типов. Например, если для значения класса Pair нужно использовать
исключительно классы типа Number и никакие другие.
Для этого применяют ограничения, которые позволяют указать базовый класс,
которому должен соответствовать параметр.
Абстрактный класс Number является суперклассом для классов,
представляющих числовые значения, преобразуемые в примитивные типы byte,
double, float, int, long и short.
При такой записи <V extends Number> компилятор не даст использовать не
унаследованные от Number классы
29
30.
Способ ограничить типизациюПопробуем создать экземпляр параметризованного класса Pair, при
такой записи у нас все хорошо, мы используем числа
Double, Long, Integer –
это наследники Number
А теперь специально укажем неправильный тип String:
String – не наследник Number
И получим ошибку компиляции
30
31.
Различия обычных классов и типизированныхСвойство
Обычный класс
Типизированный класс
Синтаксис
Pair pair = new Pair();
Pair<String> pair = new Pair<>();
Безопасность Может содержать данные
любого типа, а значит, не
обеспечивает типовую
безопасность.
Может содержать только
определённый тип данных.
Является типобезопасным.
Приведение
Приведение типа
Приведение типов не
необходимо выполнять при требуется.
каждом обращении.
Проверки
компиляции
Проверяется на
безопасность типов во
время выполнения.
Проверяется на безопасность
типов во время компиляции.
31
32.
Итоги• Чтобы избежать создания множества похожих классов по
функциональности, рекомендуется использовать обобщенные типы
(дженерики).
• Старайтесь не использовать необработанные типы обобщений.
• Применяйте алмазный синтаксис.
• Большинство коллекций в Java поддерживают обобщения.
• Типы могут быть параметризованны в конструкторах, методах,
классах и интерфейсах.
• Ограничения на параметры типов позволяют сузить круг
разрешённых для использования типов.
32
33.
Задача 1: Обобщенный контейнерОписание:
Создайте обобщенный класс Container с двумя полями. Этот класс должен хранить два
объекта различных типов, например, T и U. Реализуйте методы для получения и
установки значений каждого объекта, а также метод swap, который меняет местами
значения этих объектов.
Требования:
1. Создайте класс Container<T, U>.
2. Реализуйте методы getFirst(), setFirst(T value), getSecond(), setSecond(U value).
3. Реализуйте метод swap(), который меняет местами значения первого и второго
объектов и возвращает новый Container <U,T>
4. Напишите тест, в котором создаете экземпляр Container<Integer, String> и
продемонстрируйте использование всех методов.
33
34.
Задача 2: Ограниченные дженерикиОписание:
Создайте обобщенный класс NumberBox, который принимает только числовые типы
(например, Integer, Double, Float и т.д.). Реализуйте метод sum для вычисления суммы
всех чисел и метод average для подсчета среднего числа.
Требования:
1. Создайте класс NumberBox<T extends Number>.
2. Внутри класса храните List<T>, куда можно добавлять числа.
3. Реализуйте метод add(T number) для добавления числа в список.
4. Реализуйте метод sum(), который возвращает сумму всех чисел в списке
5. Реализуйте метод average(), который возвращает среднее всех чисел в списке
6. Напишите тест, в котором создаете экземпляр NumberBox<Double> (или другого
числового типа), добавляете несколько чисел, и выводите их сумму.
34
35.
Задача 3: Универсальная коллекцияОписание задачи:
Реализуйте универсальную коллекцию с использованием Generics, которая
хранит элементы любого типа. Коллекция должна предоставлять базовую
функциональность: добавление, удаление и получение элементов.
35
36.
Задача 3: Универсальная коллекцияТребования:
1. Создание класса GenericCollection<T>:
- Реализуйте класс с использованием Generics, где T представляет тип
элементов в коллекции.
- В классе должен быть внутренний массив для хранения элементов.
Изначально он может быть размером 10.
2. Методы для работы с элементами:
- void add(T element): добавляет элемент в коллекцию. Если массив
заполнен, увеличьте его размер вдвое.
- T get(int index): возвращает элемент по заданному индексу. Если индекс
выходит за пределы количества элементов, выбросьте исключение
IndexOutOfBoundsException.
- void remove(int index): удаляет элемент по заданному индексу и сдвигает
оставшиеся элементы влево. Если индекс недопустим, также выбросьте
IndexOutOfBoundsException.
- int size(): возвращает текущее количество элементов в коллекции.
36
37.
Задача 3: Универсальная коллекция3. Тестирование:
- Напишите тесты, которые проверяют работу класса GenericCollection с
различными типами данных: например, Integer, String и пользовательские
классы.
Рекомендации:
- Используйте массив объектов Object[] для внутреннего хранения и
приведение типов в методах для реализации generics.
- Обратите внимание на обработку исключений и проверку индексов.
Пример использования:
GenericCollection<String> stringCollection = new GenericCollection<>();
stringCollection.add("Hello");
stringCollection.add("World");
System.out.println(stringCollection.get(0)); // Output: Hello
stringCollection.remove(1);
System.out.println(stringCollection.size()); // Output: 1
37
Программирование