2010-08-10 3 views
4

Учитывая два класса, как это:Java Дженерики Отражение: Generic тип поля подкласса

class Example1<A,B> { 

    public Map<A,B> someMap = new HashMap<A,B>(); 

} 

class Example2 extends Example1<URL, URL> { 


} 

Есть ли способ, с помощью отражения, что я могу определять типы компонентов на карте для example2?

Я знаю, что я могу сделать:

ParameterizedType t = (ParameterizedType) Example2.class.getFields()[0].getGenericType(); 

Но оттуда, я не могу показаться, чтобы выяснить, что два компонента URL-адреса.

У кого-нибудь есть идеи?

+0

Просто любопытно ... Что бы 'т' содержать? – danyim

+2

dont никогда не использовать java.net.URL как ключ для HashMap !! это зло, потому что это потенциально часто вызывает hostsEqual(), который выполняет сетевые операции ввода/вывода (dns lookups). – mhaller

ответ

1

Поскольку Java-генераторы реализованы с помощью «стирания», эта информация недоступна во время выполнения через отражение.

EDIT: кажется, я пропустил какую-то деталь вопроса. В этом виде специализированного случая доступна информация о типе.

+1

. Было бы правильно, если бы отражение началось с вызова 'getClass' на экземпляре' HashMap 'себя. Тогда код Кирка напечатает что-то вроде 'K' и' V' (имена параметров типа, довольно бесполезные). Но поскольку отражение здесь начинается с класса, который * наследует * 'HashMap ', типы, предоставленные для 'K' и' V', хранятся в метаданных класса для 'Example2', поэтому код Kirk содержит некоторую информацию для чтения из , –

+0

Роб спрашивает о классе, а не об объекте. Информация доступна во время выполнения. –

7

Darron не совсем корректен. Далее будет распечатать то, что вы хотите:

ParameterizedType superClass = (ParameterizedType) Example2.class.getGenericSuperclass(); 
System.out.println(superClass.getActualTypeArguments()[0]); 
System.out.println(superClass.getActualTypeArguments()[1]); 

Печатает:

class java.net.URL 
class java.net.URL 
+0

Чтобы уточнить точку «стирание типа», вся информация общего типа фактически закодирована в файле Java .class. Там, где это ** не ** закодировано, находится в процессе выполнения метода. Вот почему информация доступна через отражение, но недоступна через стандартные языковые конструкции (т. Е. Новый T [] или o instanceof T). –

+0

Это дает вам параметры типа, используемые в примере2 для своего * прямого * суперкласса. Но для решения общей проблемы, поставленной этим вопросом, вам нужно найти параметры типа для произвольного суперкласса, а затем заменить переменные типа, возможно, глубоко внутри типа поля. getGenericSuperclass() - это лишь маленький первый шаг для достижения этой цели. Существует много (иногда сложных) дел, связанных с построением полного решения. Я бы не рекомендовал (а) реализовать это самостоятельно, если вы не * действительно * в дженериках. –

1

Ваш ответ не совсем правильно - вы возвращаете общие типы класса, а не «someMap» типа поля ,

Конечно, в приведенном примере аргументы someMap были такими же, как и аргументы класса, но если someMap был определен, а типы карт не были оба URL, тогда возникает вопрос о как сопоставить параметры родового типа с полем.

Лучший пример может быть:

class Example1<A,B> { 

    public Map<B,A> someMap = new HashMap<B,A>(); 

} 

class Example2 extends Example1<URL, String> { 


} 

В этом случае, чтобы ответить на вопрос: какие типы someMap в в example2? Ответ должен быть:

java.lang.String java.net.URL

Но я до сих пор не могу понять, как получить это.

1

Отражение API Java не есть метод, который непосредственно дает то, что вы хотите, но это не подвергать всю основную информацию, необходимую, чтобы иметь возможность стоимость его Field.getGenericType() и Class.getGenericSuperclass(). Но решение этой проблемы вообще для любой иерархии классов и типа поля не является тривиальным.

Для этого расчет вы можете использовать библиотеку gentyref. В вашем примере, вы можете получить тип переменной someMap так:

Type someMapType = GenericTypeReflector.getExactFieldType(
    Example2.class.getField("someMap"), 
    Example2.class); 

Если достаточная информация доступна (и в example2, то есть), someMapType будет ParameterizedType.Тогда вы можете получить тип ключа и значения, как это:

((ParameterizedType)someMapType).getActualTypeArguments(); 

Это будет массив, содержащий URL.class дважды. Обратите внимание, что он может содержать и другие вещи, кроме классов (например, другой параметр ParameterizedType). Поэтому, если вы хотите сделать что-то нетривиальное с этим типом (например, посмотрите, является ли это супертипом другого), другие методы в GenericTypeReflector тоже могут оказаться полезными ...

[Я являюсь автором gentyref]

Смежные вопросы