История вопроса:
В Generics Java были введены в Java 5 для обеспечения безопасной работы с типами коллекций и методов, однако реализованы были с поддержкой обратной совместимости с ранее написанным байткодом. Для этого был применён механизм type erasure (стирание типов).
Проблема:
Компилятор Java требует строгой типизации, однако во время выполнения JVM не знает о параметрах типизации, а многие старые классы и библиотеки, включая саму коллекционную библиотеку Java, работают с универсальными "сырыми" типами (raw types). Без обратной совместимости невозможно было поддерживать существующие разработки.
Решение:
Type erasure — это процесс преобразования параметризованных типов (дженериков) к их "сырым" версиям, чтобы JVM могла работать с уже существующим байткодом без изменений. Вся информация о параметрах типа удаляется на этапе компиляции, вместо неё используются объекты типа Object (или ограничение, если указано через extends).
Пример кода:
List<String> stringList = new ArrayList<>(); stringList.add("hello"); String s = stringList.get(0); // get возвращает Object, но компилятор вставляет cast
Ключевые особенности:
List<String>, List<Integer>, и т.п.Можно ли использовать перегрузку методов только по параметрам дженериков?
Нет. Из-за type erasure компилятор считает методы с одинаковыми именами и различными параметрами дженериков одинаковыми, так как параметры будут стёрты. Например,
// Ошибка компиляции! void process(List<String> list) { } void process(List<Integer> list) { }
Можно ли создать массив дженерикового типа?
Нет напрямую. Type erasure не позволяет JVM хранить массив конкретного дженерикового типа, например,
List<String>[] array = new List<String>[10]; // Ошибка компиляции
Можно обойти с помощью массива сырых типов, но это небезопасно:
List<String>[] array = (List<String>[]) new List[10];
Можно ли проверить тип дженерика в runtime через instanceof?
Нет, так как информация о параметрах стирается. Проверка:
if (obj instanceof List<String>) { ... } // Ошибка компиляции
Правильнее — проверять только основной тип:
if (obj instanceof List) { ... }
Программист создаёт массив параметризованных типов для хранения списков разных параметров. В итоге после длительной работы программы возникает ClassCastException при извлечении объекта из массива — типизация в рантайме не обеспечивается.
Плюсы:
Минусы:
Вместо массивов используются коллекции (например, List<List<String>>), и все проверки типов делегируются компилятору.
Плюсы:
Минусы: