Я хочу попытаться разбить ответ @DerMike, чтобы объяснить:
Во-первых, стирание типа не означает, что JDK удаляет информацию о типе во время выполнения. Это метод, позволяющий сосуществовать проверке типов во время компиляции и совместимости типов во время выполнения на одном языке. Как следует из этого блока кода, JDK сохраняет стертую информацию о типе - она просто не связана с проверенными приведениями и прочим.
Во-вторых, это предоставляет информацию об общем типе универсальному классу ровно на один уровень выше по иерархии от проверяемого конкретного типа - т. Е. Абстрактный родительский класс с параметрами универсального типа может найти конкретные типы, соответствующие параметрам его типа, для конкретной реализации самого себя. что напрямую от него наследуется. Если бы этот класс не был абстрактным и был создан, или конкретная реализация была бы на два уровня ниже, это не сработало бы (хотя немного подергивания могло бы заставить его применяться к любому заранее определенному количеству уровней выше одного или до самого низкого класса. с параметрами универсального типа X и так далее).
Во всяком случае, к объяснению. Вот снова код, разделенный на строки для удобства:
1 # Класс genericParameter0OfThisClass =
2 # (класс)
3 # ((ParameterizedType)
4 # getClass ()
5 # .getGenericSuperclass ())
6 # .getActualTypeArguments () [0];
Пусть «нас» будет абстрактным классом с универсальными типами, который содержит этот код. Читая это примерно наизнанку:
- Строка 4 получает экземпляр класса текущего конкретного класса. Это определяет конкретный тип нашего непосредственного потомка.
- Строка 5 получает супертип этого класса как Тип; это мы. Поскольку мы параметрический тип, мы можем безопасно привести себя к ParameterizedType (строка 3). Ключ в том, что когда Java определяет этот объект Type, он использует информацию о типе, присутствующую в дочернем элементе, для связывания информации о типе с нашими параметрами типа в новом экземпляре ParameterizedType. Итак, теперь мы можем получить доступ к конкретным типам для наших дженериков.
- Строка 6 получает массив типов, отображаемых в наши обобщенные типы, в порядке, объявленном в коде класса. Для этого примера мы извлекаем первый параметр. Это возвращается как Тип.
- Строка 2 приводит последний тип, возвращаемый классу. Это безопасно, потому что мы знаем, какие типы могут принимать параметры нашего универсального типа, и можем подтвердить, что все они будут классами (я не уверен, как в Java можно было бы получить общий параметр, у которого нет экземпляра класса связанные с этим, собственно).
... и это почти все. Таким образом, мы отправляем информацию о типе из нашей собственной конкретной реализации обратно в себя и используем ее для доступа к дескриптору класса. мы могли бы удвоить getGenericSuperclass () и перейти на два уровня или исключить getGenericSuperclass () и получить значения для себя как конкретного типа (предостережение: я не тестировал эти сценарии, они еще не подошли для меня).
Это становится сложно, если ваши конкретные дети находятся на произвольном расстоянии от вас, или если вы конкретны, а не окончательны, и особенно сложно, если вы ожидаете, что у любого из ваших (с разной глубиной) детей будут свои собственные дженерики. Но обычно вы можете проектировать, исходя из этих соображений, так что это поможет вам в большинстве случаев.
Надеюсь, это кому-то помогло! Я понимаю, что этот пост старый. Я, вероятно, уберу это объяснение и оставлю его для других вопросов.