Generics

Java Collections
5 уровень , 3 лекция
Открыта

— Привет, Амиго!

— Привет, Элли!

— Сегодня мы с Ришей собираемся рассказать тебе все о generic’ах.

— Так я уже вроде бы почти все знаю.

— Почти все, да не все.

— Да? Ладно, я готов слушать.

— Тогда начнем.

Generic’ами в Java, называют классы, которые содержат типы-параметры.

Причины появления generic’ов – см. комментарий в коде:

Пример
ArrayList stringList = new ArrayList();
stringList.add("abc"); //добавляем строку в список
stringList.add("abc"); //добавляем строку в список
stringList.add( 1 ); //добавляем число в список

for(Object o: stringList)
{
 String s = (String) o; //тут будет исключение, когда дойдем до элемента-числа
}

Как решают проблему Generic’и:

Пример
ArrayList<String> stringList = new ArrayList<String>();
stringList.add("abc"); //добавляем строку в список
stringList.add("abc"); //добавляем строку в список
stringList.add( 1 ); //тут будет ошибка компиляции

for(Object o: stringList)
{
 String s = (String) o; 
}

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

— Я это уже знаю.

— Вот и отлично. Повторение — мать учения.

Но разработчики Java немного схалявили при создании Generic и вместо того, чтобы делать полноценные типы с параметрами прикрутили хитрую оптимизацию. На самом деле в типы не добавили никакой информации о их типах-параметрах, а вся магия происходила на этапе компиляции.

Код с generic’ами
List<String> strings = new ArrayList<String>();
strings.add("abc"); 
strings.add("abc");
strings.add( 1); // тут ошибка компиляции

for(String s: strings)
{
 System.out.println(s);
}
Что происходит на самом деле
List strings = new ArrayList();

strings.add((String)"abc"); 
strings.add((String)"abc");
strings.add((String) 1); //ошибка компиляции

for(String s: strings)
{
 System.out.println(s);
}

— Хитро, да.

— Да, но у этого подхода есть побочный эффект. Внутри класса-generic’а не хранится никакой информации о его типе-параметре. Такой подход позже назвали стиранием типов.

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

Код с generic’ами
class Zoo<T>
{
 ArrayList<T> pets = new ArrayList<T>();

 public T createAnimal()
 {
  T animal = new T();
  pets.add(animal)
  return animal;
 }
}
Что происходит на самом деле
class Zoo
{
 ArrayList pets = new ArrayList();

 public Object createAnimal()
 {
  Object animal = new ???();
 pets.add(animal)
  return animal;
 }
}

При компиляции все типы параметров заменяются на Object. И информации о типе, который в него передавали, в классе нет.

— Да, согласен, это не очень хорошо.

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

Но и это еще не все. Java позволяет задать тип-родитель для типов-параметров. Для этого используется ключевое слово extends. Пример:

Код с generic’ами
class Zoo<T extends Cat>
{
 T cat;

 T getCat()
 {
  return cat;
 }

 void setCat (T cat)
 {
  this.cat = cat;
 }

 String getCatName() { return this.cat.getName(); }
}
Что происходит на самом деле
class Zoo
{
 Cat cat;

 Cat getCat()
 {
  return cat;
 }

 void setCat(Cat cat)
 {
  this.cat = cat;
 }

 String getCatName() { return this.cat.getName(); }
}

Обрати внимание на два факта.

Во-первых, в качестве типа параметра теперь можно передать не любой тип, а тип Cat или один из его наследников.

Во-вторых, в классе Zoo у переменных типа T теперь можно вызвать методы класса Cat. Почему – объяснено в столбце справа (потому что вместо типа T везде подставится тип Cat)

— Ага. Если мы сказали, что в качестве типа-параметра у нас передают тип Cat или его наследников, значит, мы уверены, что методы класса Cat у типа T обязательно есть.

Что ж. Умно.

Комментарии (37)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Denis Odesskiy Уровень 47
14 ноября 2024
"Но разработчики Java немного схалявили при создании Generic"... Это было сделано не потому что "они схалявили", а для обратной совместимости с кодом в котором этих самых дженериков не было. Например в C# если мне память не изменяет, типы не стираются.... Статья Стирание типов
Алексей С Уровень 33
7 июля 2023
А когда будут соники))
Deniel Уровень 42
10 января 2023
Дженерики и вправду полезная штука
wokku Уровень 51
17 июля 2023
😂
Виктор Уровень 1
8 декабря 2022
Простое и понятное объяснение: Дженерики в Java для самых маленьких: синтаксис, границы и дикие карты Еще хорошее объяснение есть на метаните (ищите ссылку ниже) Ну и что бы было у всех на виду, буквы дженериков: E — element, для элементов параметризованных коллекций; K — key, для ключей map-структур; V — value, для значений map-структур; N — number, для чисел; T — type, для обозначения типа параметра в произвольных классах; S, U, V и так далее — применяются, когда в дженерик-классе несколько параметров. The Java™ Tutorials - Generic Types
Maks Panteleev Уровень 41
15 июля 2021
Дженерики это как рекурсия и this - ты либо чувствуешь сердцем, либо таращишь глаза и плачешь
Hidden #213 Уровень 48
27 марта 2022
😭😭😭 как боженька смолвил
Oleg Khilko Уровень 51
9 августа 2022
Макс, ты шикарен!💪👍 Отлично сказано!
FatCat Уровень 51
28 сентября 2022
Восхитительно сказал, я даже сквозь слезы твой коммент смог прочитать)
Limone Уровень 39
28 января 2021
Просто пропиарю здесь огромный FAQ по дженерикам из рекомендаций Хорстманна, куда можно заглядывать каждый раз, когда забыл, как быстро и с гарантией устроить heap pollution, или задаёшься смутными вопросами "Можно ли заоверрайдить дженерик метод другим дженерик методом?" "Почему нет enum-дженериков?" и "Кто такая эта ваша реификация".)
NikeMirum Уровень 41
20 октября 2020
Вроде бы простая тема, но у меня почему-то вызвала больше всего недоумения из всех пройденных. Особенно сложно въезжать было в: "Но разработчики Java немного схалявили при создании Generic и вместо того, чтобы делать полноценные типы с параметрами прикрутили хитрую оптимизацию. На самом деле в типы не добавили никакой информации о их типах-параметрах, а вся магия происходила на этапе компиляции."
Максим Уровень 36
5 марта 2020
Очередная лекция на наркоманском языке. И как всегда комментарии рулят )))
Vorlock Уровень 31
23 января 2020
в сэмпле "Код с generic’ами" и "Что происходит на самом деле" ошибка в 8й строке - пропущен ";" и что это за ересь "Object animal = new ???();" зы: за такой стайл написания на проектах ногами бьют
Justinian Уровень 41 Master
2 мая 2020
злые у вас там на проекте, постарайся больше так не подставляться
Даниил Уровень 41 Master
8 сентября 2019
Кто не понял, тот поймёт. - Сергей Дружко. Обобщения (Generics)
5 декабря 2019
Я по ходу тот самый кто должен понять;)