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

Generics: ? wildcard

Открыта

— Ну, и напоследок еще одна маленькая лекция по 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, 02:15
Факт ДНЯ для комментов ниже: Использование Class<T> в generic-классах — мощный способ сделать гибкие и при этом безопасные фабрики объектов.
23 декабря 2024, 15:30
зачем явно прописывать в конструкторе еще раз, если можно через рефлексию, нет?
Ra
Уровень 19
Student
24 июля 2023, 19:29
Ещё есть getGenericSuperclass()
LeX
Уровень 12
28 сентября 2022, 12:45
Вдруг кому-то пригодится, чтобы точно закрепить - Java generics. В чем разница между wildcard(<?>) и parameterized types(<T>)?
Nik Grape
Уровень 48
16 ноября 2021, 03:15
Java с блекджеком и … называется Kotlin
Ilia lenskii
Уровень 32
17 сентября 2022, 11:00
". Давай до свидания."
Ra
Уровень 19
Student
24 июля 2023, 10:45
или C#
Max Zap
Уровень 41
1 ноября 2021, 09:06
Этот метод deprecated c 9 версии. Вместо него используется нынче clazz.getDeclaredConstructor().newInstance(). docs.oracle.com
Сергей ЖирковBackend Developer в MvideoMobile
25 сентября 2021, 01:38
Это вообще хоть где-то пригодится?))
25 сентября 2021, 08:20
Дают значит надо .Я просто читаю интересно хоть и сложно без практики .
МихаилFull Stack Developer в финтех
17 февраля 2022, 19:07
Да, пригодится. Например, когда нужно будет работать с различными наследниками одного предка, но при этом избежать преобразования типов, т.к. это ограничивает полиморфизм.
СергейJava Developer в Адвантум
27 июля 2021, 17:23
Пц! Это вообще что?! Такое ощущение, что блок Collections делали по принципу "и так сойдет". — Ага. Понимаю. Ничего сверхъестественного не произошло и страшного тоже. Ссылка на тип есть, пользоваться ей можно, работает и ладно. — Вот, слышу слова «не мальчика, но мужа!» Работает и ладно – это часто самый оптимальный вариант.
LuneFoxJava Developer в BIFITExpert
1 февраля 2022, 16:42
Igor Petrashevsky
Уровень 47
25 августа 2022, 00:12
это было понятно с появлением глубокопродуманной переменной с именем clazz
Андрей
Уровень 51
14 мая 2024, 06:42
просто class ключевое слово
Valua Sinicyn
Уровень 41
15 февраля 2021, 07:44
Если бы еще "мегахитрая комбинация" компилировалась, было бы вообще супер. А так, очередной сферический конь.
Vova Enin
Уровень 5
10 сентября 2021, 07:01
Все отлично компилируется
Хорс
Уровень 41
28 августа 2020, 13:43
Мне оч помогло это разъяснение: https://stackoverflow.com/questions/6231973/difference-between-list-list-listt-liste-and-listobject
ivan дворник
10 июля 2023, 15:53