JavaRush /Курсы /Java Collections /Generics: ? wildcard

Generics: ? wildcard

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

— Ну, и напоследок еще одна маленькая лекция по Generic.

Сейчас я тебе расскажу, как обходить «стирание типов» (Type erasure).

— Ага. Мне тоже хочется это знать.

— Как ты уже наверное знаешь, в Java есть тип Class, который используется, чтобы хранить ссылку на объект класса. Примеры:

Примеры
Class clazz = Integer.class;
Class clazz = String.class;
Class clazz = "abc".getClass();

— Ага.

Но вот чего ты, наверное, не знаешь, так это того, что есть еще один класс Class, который является Generic’ом. И переменные этого Generic Class’а могут хранить только ссылки на тип, который был типом-параметром. Примеры:

Примеры
Class<Integer> clazz1 = Integer.class; //все отлично работает
Class<String> clazz2 = Integer.class; //ошибка компиляции.
Class<String> clazz1 = String.class; //все отлично работает
Class<String> clazz2 = int.class; //ошибка компиляции.
Class<? extends String> clazz1 = "abc".getClass(); //все отлично работает
Class<Object> clazz2 = "abc".getClass(); //ошибка компиляции.

— А почему оно так работает?

— Дело в том, что значение поля class у типа Integer (т.е. у Integer.class) – это на самом деле объект типа Class<Integer>.

Но давай пойдем дальше.

Так вот, пользуясь тем фактом, что Class<T> — это Generic, и тем, что переменная его типа может хранить значение только типа T, можно сделать вот такую хитрую комбинацию:

Пример
class Zoo<T>
{
 Class<T> clazz;
 ArrayList<T> animals = new ArrayList<T>();

 Zoo(Class<T> clazz)
 {
  this.clazz = clazz;
 }

 public T createNewAnimal()
 {
  T animal = clazz.newInstance();
  animals.add(animal);
  return animal
 }
}
Как это использовать
Zoo<Tiger> zoo = new Zoo<Tiger>(Tiger.class); // вот тут передается тип!
Tiger tiger = zoo.createNewAnimal();

Это не мегахитрая комбинация – мы просто передаем ссылку на нужный тип. Но если бы мы просто пользовались Class вместо Class<T>, то кто-то мог по ошибке передать туда два разных типа – один в качестве параметра T, другой – в конструктор.

— Ага. Понимаю. Ничего сверхъестественного не произошло и страшного тоже. Ссылка на тип есть, пользоваться ей можно, работает и ладно.

— Вот, слышу слова «не мальчика, но мужа!» Работает и ладно – это часто самый оптимальный вариант.

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

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

— А я сделаю свою Java с блекджеком и …

— Ладно, я уже подустал за день. Давай до свидания.

— До свидания, Риша, и спасибо за такой интересный урок.

Комментарии (63)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Артём Сёмкин Уровень 47
24 апреля 2025
Факт ДНЯ для комментов ниже: Использование Class<T> в generic-классах — мощный способ сделать гибкие и при этом безопасные фабрики объектов.
23 декабря 2024
зачем явно прописывать в конструкторе еще раз, если можно через рефлексию, нет?
Ra Уровень 16 Student
24 июля 2023
Ещё есть getGenericSuperclass()
LeX Уровень 27
28 сентября 2022
Вдруг кому-то пригодится, чтобы точно закрепить - Java generics. В чем разница между wildcard(<?>) и parameterized types(<T>)?
Nik Grape Уровень 48
16 ноября 2021
Java с блекджеком и … называется Kotlin
Ilia lenskii Уровень 32
17 сентября 2022
". Давай до свидания."
Ra Уровень 16 Student
24 июля 2023
или C#
Max Zap Уровень 41
1 ноября 2021
Этот метод deprecated c 9 версии. Вместо него используется нынче clazz.getDeclaredConstructor().newInstance(). docs.oracle.com
Сергей Жирков Уровень 1
25 сентября 2021
Это вообще хоть где-то пригодится?))
25 сентября 2021
Дают значит надо .Я просто читаю интересно хоть и сложно без практики .
Михаил Уровень 41
17 февраля 2022
Да, пригодится. Например, когда нужно будет работать с различными наследниками одного предка, но при этом избежать преобразования типов, т.к. это ограничивает полиморфизм.
Сергей Уровень 32
27 июля 2021
Пц! Это вообще что?! Такое ощущение, что блок Collections делали по принципу "и так сойдет". — Ага. Понимаю. Ничего сверхъестественного не произошло и страшного тоже. Ссылка на тип есть, пользоваться ей можно, работает и ладно. — Вот, слышу слова «не мальчика, но мужа!» Работает и ладно – это часто самый оптимальный вариант.
LuneFox Уровень 41 Expert
1 февраля 2022
Igor Petrashevsky Уровень 47
25 августа 2022
это было понятно с появлением глубокопродуманной переменной с именем clazz
Андрей Уровень 51
14 мая 2024
просто class ключевое слово
Valua Sinicyn Уровень 41
15 февраля 2021
Если бы еще "мегахитрая комбинация" компилировалась, было бы вообще супер. А так, очередной сферический конь.
Vova Enin Уровень 36
10 сентября 2021
Все отлично компилируется
Хорс Уровень 41
28 августа 2020
Мне оч помогло это разъяснение: https://stackoverflow.com/questions/6231973/difference-between-list-list-listt-liste-and-listobject