Получить доступ

Что означает стирание типов (type erasure)?

JuniorДженерики
Ещё спрашивают так:
  • Почему нельзя написать new T()?
  • Почему List<String> и List<Integer> — один класс в рантайме?
  • Что такое type erasure в дженериках?
Коротко

Стирание типов: компилятор проверяет типы, но в байткоде параметр заменяется границей (обычно Object) — в рантайме его нет.

  • Сделано ради совместимости со старым кодом без дженериков
  • Нельзя: new T(), new T[], instanceof List<String>, обобщённое исключение

А ещё List<String> и List<Integer> в рантайме — один класс ArrayList

Так подсказку видит пользователь sotto на живом собеседовании — за пару секунд, пока вы думаете вслух.

Подробно

Дженерики появились в Java 5, и разработчики языка сохранили совместимость с уже написанным кодом: старые и новые классы должны были работать вместе. Поэтому параметры типов существуют только на этапе компиляции. Компилятор проверяет типы и вставляет нужные приведения, а в байткоде T заменяется на свою верхнюю границу — Object или, например, Comparable для <T extends Comparable<T>>.

Практические последствия:

  • нельзя создать объект или массив по параметру: new T(), new T[10] — тип неизвестен в рантайме;
  • нельзя проверить obj instanceof List<String> — только List<?>;
  • List<String> и List<Integer> во время выполнения — один и тот же класс;
  • нельзя перегрузить методы, отличающиеся только параметром (void f(List<String>) и void f(List<Integer>));
  • нельзя объявить обобщённый класс исключения.

Обходной путь — передавать Class<T> явно (clazz.getDeclaredConstructor() .newInstance()) или токен типа, как делают JSON-библиотеки.

Пример

List<String> a = new ArrayList<>();
List<Integer> b = new ArrayList<>();
System.out.println(a.getClass() == b.getClass()); // true

<T> T create(Class<T> type) throws Exception {
    return type.getDeclaredConstructor().newInstance();
}

Что хотят услышать

  • Определение: проверка при компиляции, параметр стёрт в байткоде.
  • Причина — обратная совместимость.
  • Практические ограничения.
  • Обходной путь через Class<T> — плюс.

Частые ошибки

  • Пытаться создать массив параметризованного типа.
  • Проверять принадлежность объекта к параметризованному типу.

Проверьте себя

Один верный вариант. Подумайте, потом откройте ответ.

Показать варианты и ответ
  • ✓Компилятор проверяет типы, но в байткоде параметр заменяется на его верхнюю границу — во время выполнения информации о нём нет
  • ✗Параметр типа удаляется из исходного кода при форматировании
  • ✗Значения параметризованных полей обнуляются сборщиком мусора
  • ✗Компилятор генерирует отдельный класс для каждой параметризации

Что спросят дальше

  • Как обойти невозможность создать объект по параметру типа?
  • Почему нельзя объявить обобщённый класс исключения?
  • Что такое PECS?
  • Почему нельзя new T[]?

Разбор темы

Связанные вопросы

Закрытая бета

Подсказки на собеседовании — в реальном времени

sotto слышит вопрос интервьюера и показывает короткий ответ и план, как в блоке «Коротко». Оставьте контакт — пришлём доступ и промокод.

  • Промокод на 2 часа — сверх пробных 30 минут
  • Программа для Windows — скачать сразу, войти — через Яндекс ID или VK ID
  • Прямая связь с разработчиком: что улучшить — сделаем