Что означает стирание типов (type erasure)?
- Почему нельзя написать 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[]?
Разбор темы
- Дженерики: массивы, varargs и bridge-методы
Почему дженерики не дружат с массивами, heap pollution и @SafeVarargs, синтетические bridge-методы и reifiable-типы.
- Дженерики и стирание типов
Типобезопасность на компиляции, механизм type erasure и его последствия, дженерик-методы, ограниченные параметры и опасность raw types.
Связанные вопросы
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.