Get type of a generic parameter in Java with reflection
Получить тип универсального параметра в Java с отражением
Возможно ли получить тип универсального параметра?
Пример:
publicfinalclassVoodoo { publicstaticvoidchill(List<?> aListWithTypeSpiderMan) { // Here I'd like to get the Class-Object 'SpiderMan' ClasstypeOfTheList= ???; }
Итак, похоже, что вокруг есть какая-то магия отражения, которую я, к сожалению, не до конца понимаю... Извините.
Ответ 2
Я хочу попытаться разобрать ответ от @DerMike, чтобы объяснить:
Во-первых, удаление типа не означает, что JDK удаляет информацию о типе во время выполнения. Это метод, позволяющий сосуществовать проверке типов во время компиляции и совместимости типов во время выполнения на одном языке. Как следует из этого блока кода, JDK сохраняет удаленную информацию о типе - она просто не связана с проверенными приведениями и прочим.
Во-вторых, это предоставляет информацию об универсальном типе универсальному классу ровно на один уровень выше по иерархии от проверяемого конкретного типа - т. Е. Абстрактный родительский класс с параметрами универсального типа может найти конкретные типы, соответствующие его параметрам типа, для конкретной реализации самого себя, которая непосредственно наследуется от него. Если бы этот класс был неабстрактным и создавался в виде экземпляра, или конкретная реализация была бы на два уровня ниже, это бы не сработало (хотя небольшая доработка могла бы заставить его применяться к любому заранее определенному количеству уровней, превышающему один, или вплоть до самого низкого класса с параметрами X универсального типа, и так далее).
В любом случае, перейдем к объяснению. Вот снова код, разделенный на строки для удобства использования:
Пусть 'us' будет абстрактным классом с универсальными типами, который содержит этот код. Читаем это примерно наизнанку.:
Строка 4 возвращает экземпляр класса текущего конкретного класса. Это идентифицирует конкретный тип нашего непосредственного потомка.
Строка 5 получает супертип этого класса в качестве типа; это us . Поскольку мы являемся параметрическим типом, мы можем безопасно привести себя к ParameterizedType (строка 3). Ключ в том, что когда Java определяет этот объект типа, она использует информацию о типе, присутствующую в дочернем объекте, чтобы связать информацию о типе с нашими параметрами типа в новом экземпляре ParameterizedType . Итак, теперь мы можем получить доступ к конкретным типам для наших дженериков.
Строка 6 возвращает массив типов, отображенных в наши общие параметры, в порядке, объявленном в коде класса. В этом примере мы извлекаем первый параметр. Он возвращается как тип.
Строка 2 приводит конечный тип, возвращаемый классу. Это безопасно, потому что мы знаем, какие типы могут принимать наши параметры универсального типа, и можем подтвердить, что все они будут классами (я не уверен, как в Java можно получить универсальный параметр, с которым на самом деле не связан экземпляр класса).
...и это в значительной степени все. Итак, мы переносим информацию о типе из нашей собственной конкретной реализации обратно в себя и используем ее для доступа к дескриптору класса. мы могли бы удвоить getGenericSuperclass() и перейти на два уровня, или исключить getGenericSuperclass() и получить значения для себя как конкретный тип (предостережение: я не тестировал эти сценарии, они еще не придуманы для меня).
Это становится сложным, если ваши конкретные дочерние элементы находятся на расстоянии произвольного количества переходов, или если вы конкретный, а не окончательный вариант, и особенно сложно, если вы ожидаете, что у любого из ваших (с переменной глубиной) дочерних элементов будут свои собственные обобщения. Но обычно вы можете проектировать с учетом этих соображений, так что это поможет вам в большей степени.
Надеюсь, это кому-то помогло! Я признаю, что этот пост древний. Я, вероятно, сокращу это объяснение и сохраню его для других вопросов.
Ответ 3
На самом деле я заставил это работать. Рассмотрим следующий фрагмент:
Method m; Type[] genericParameterTypes = m.getGenericParameterTypes(); for (inti=0; i < genericParameterTypes.length; i++) { if( genericParameterTypes[i] instanceof ParameterizedType ) { Type[] parameters = ((ParameterizedType)genericParameterTypes[i]).getActualTypeArguments(); //parameters[0] contains java.lang.String for method like "method(List<String> value)"
publicfinalclassVoodoo { publicstaticvoidchill(final List<?> aListWithSomeType) { // Here I'd like to get the Class-Object 'SpiderMan' System.out.println(aListWithSomeType.getClass().getGenericSuperclass()); System.out.println(((ParameterizedType) aListWithSomeType .getClass() .getGenericSuperclass()).getActualTypeArguments()[0]); } publicstaticvoidmain(String... args) { chill(newArrayList<SpiderMan>() {}); } } classSpiderMan { }
Хитрость заключается в создании анонимного класса, new ArrayList<SpiderMan>() {} вместо исходного (простого) new ArrayList<SpiderMan>(). Использование анонимного класса (если возможно) гарантирует, что компилятор сохранит информацию о аргументе типа, SpiderMan заданном параметру типа List<?>. Voilà !