Насколько я понимаю, дженерики — это функция времени компиляции Java, а информация о параметризованном типе не существует в скомпилированном байтовом коде. Теперь я обнаружил методы Field#getGenericType и Method#getGenericReturnType, что разрушило мое мировоззрение. Пожалуйста, помогите мне собрать его воедино.
стирание типа Java по сравнению с Field#getGenericType и Method#getGenericReturnType
Ответы (3)
Типы объектов только во время выполнения стираются. Например:
Object obj = new ArrayList<String>();
obj.getClass()
вернет ArrayList.class
. Можно даже сказать, что ArrayList
имеет общий параметр. Но невозможно определить, был ли obj
создан как ArrayList<String>
, ArrayList<Integer>
, ArrayList<Object>
, ArrayList
(необработанный) или как-то еще.
Информация о статическом типе по-прежнему существует для классов, методов и т. д. (хотя и не для локальных). Это всего лишь дополнительный бит данных, добавленный в качестве атрибутов в файле класса и доступный во время выполнения. Думайте об этом так же, как об аннотациях с сохранением во время выполнения. Был вопрос?
Когда вы имеете дело с банкой скомпилированного байт-кода в своей среде IDE, вы все равно можете получить универсальное автозаполнение. Вот так это реализовано. В основном вы правы: типы не стираются полностью.
Информация о статическом универсальном типе для полей и методов должна присутствовать в скомпилированном файле класса, чтобы при компиляции другого исходного кода компилятор мог выполнять проверку типов. Например, когда вы пишете код, использующий переменную типа ArrayList<E>
, и вызываете для нее метод get()
, у вас нет исходного кода для класса ArrayList
. Компилятор просматривает скомпилированный файл класса и получает универсальный возвращаемый тип метода get()
и понимает, что он возвращает универсальный тип E
, чтобы он мог выполнять проверку типов. Таким образом, информация об универсальном типе должна присутствовать, чтобы компилятор мог ее проверить.