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 с блекджеком и …

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

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

Комментарии (41)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Underdante
Уровень 69
24 апреля, 16:25
я не понял пример с zoo , мы ж там только один класс создать можем , тогда почему zoo. zoo - это ж зоопарк , зоопарк с одними тиграми такое себе. или я не понял?
Георгий
Уровень 93
3 февраля, 18:06
Задача "Wildcards для коллекций" раковая, пожалуйста добавьте валидатору решение с concat() хотя бы через CharSequence, всю голову сломал - зная что String final, а валидатор все равно требует wildcart
Виталий
Уровень 31
13 декабря 2025, 10:35
Лекция по дженерикам - 💩. Зачем, почему, как правильно использовать?
Andrei Miroshnichenko
Уровень 1
5 августа 2025, 14:09
как только попадается сложная тема, так авторы по полной обсираются. в очередной раз приходится обращаться к чату и гуглу
Иван
Уровень 115
26 марта 2025, 09:39
Тот кто писал эти лекции, не пытался сам их прочитать, материал подан ужасно. Несуразные радуга цветов и "диалог", и полное непонимание происходящего у того, кто читает
Arthur Kozlov
Уровень 115
24 марта 2025, 16:58
Перед тем как нажать кнопку "Открыть следующую лекцию", слышу знакомый саундтрек и понимаю что еще вернусь сюда.
Денис
Уровень 68
25 января 2025, 03:27
В 3-й задаче я сделал так: public static String concat(List<? extends Object> list) { StringBuilder builder = new StringBuilder(); for (Object obj : list) { builder.append(obj); } return builder.toString(); }
Кирилл
Уровень 115
21 января 2025, 13:57
По всему уровню ничего не понятно. Тема не раскрыта, от слова совсем. Чем дальше, тем, видимо, хуже будет подан материал. Либо к этому моменту мы должны уже иметь общее понимание как программировать и такие темы должны быть понятны и без разжевывания (лично у меня такого нет), либо разработчики учебных материалов начали халтурить.
Денис
Уровень 68
22 января 2025, 14:25
Да, тема с дженериками с ходу не зашла, придётся несколько раз перечитывать. Местами непонятно совсем.
Артем
Уровень 48
19 февраля 2025, 15:27
+1 Что-то совсем печально даются мне эти дженерики...
Виктор Ш
Уровень 3
20 марта 2025, 20:42
Пишется весело. Но мне трудно уследить за нитью. Примеры очень абстрактны.
Роман
Уровень 47
23 февраля, 19:04
А смысл такое перечитывать? Гугл, Ютуб, Хабр. Надежда только на них.
Максим
Уровень 115
17 января 2025, 17:03
— Как ты уже наверное знаешь, в Java есть тип Class, который используется, чтобы хранить ссылку на объект класса. Нет, первый раз слышу... Ничего не понятно.
6 октября 2024, 16:29
Деньги заплатили и ладно, объяснять не обязательно. Диалог дурацкий, лучше больше объяснений.