— Ну, и напоследок еще одна маленькая лекция по 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 с блекджеком и …

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

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