Вопрос с собеседования · Java

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

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

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

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

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

Подробно

Дженерики появились в 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

После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.

Разбор собеседования