2009-07-14 2 views
5

Я хотел бы получить общий тип коллекции с использованием отражения во время выполнения.Задание типичного типа коллекции param во время выполнения (Java Reflection)

код (JAVA):

Field collectionObject = object.getClass().getDeclaredField(
    collectionField.getName()); 
//here I compare to see if a collection 
if (Collection.class.isAssignableFrom(collectionObject.getType())) { 
    // here I have to use the generic type of the collection 
    // to see if it's from a specific type - in this case Persistable 
    if (Persistable.class.isAssignableFrom(GENERIC_TYPE_COLLECTION.class)) { 
    } 
} 

Есть ли способ получить общий вид коллекции в Java во время выполнения? В моем случае мне нужен класс. Класса общего типа коллекции.

Заранее спасибо!

+0

Я столкнулся с подобной проблемой, и это то, что окончательно разрешило это для меня: http://stackoverflow.com/a/183232/639119 – Zds

ответ

17

Type erasure означает, что информация об общем типе объекта просто отсутствует во время выполнения.

(ссылка на соответствующий раздел Java Generics FAQ Анжелики Лангера, который должен ответить практически на любой вопрос вы могли бы спросить о Java дженериков :)

Однако, вы на самом деле не заинтересованы в типе объекта - вас интересует тип поля . Я неправильно понял вопрос, и хотя ответ был принят, я надеюсь внести исправления, исправив его сейчас :)

Если поле не использует параметр типа, оно может быть выполнено. Например:

import java.lang.reflect.*; 
import java.util.*; 

public class Test 
{ 
    public List<String> names; 

    public static void main(String [] args) 
     throws Exception // Just for simplicity! 
    { 
     Field field = Test.class.getDeclaredField("names"); 

     ParameterizedType type = (ParameterizedType) field.getGenericType(); 

     // List 
     System.out.println(type.getRawType()); 

     // Just String in this case 
     for (Type typeArgument : type.getActualTypeArguments()) 
     { 
      System.out.println(" " + typeArgument); 
     } 
    } 
} 

Если поле было в классе T с полем быть List<T> то вы должны были бы знать аргумент типа для этого экземпляра, чтобы знать тип аргумента для коллекции.

Перевод этого кода в ваш требуемый код несколько сложнее - вам действительно нужно знать аргумент типа в точке класса коллекции. Например, если кто-то заявил:

public class StringCollection implements Collection<String> 

, а затем имел поле типа StringCollection, что поле само по себе не будет иметь каких-либо аргументов типа. Затем вам нужно будет проверить getGenericSuperType и getGenericInterfaces рекурсивно, пока вы не найдете то, что хотите.

Это действительно нелегко сделать, хотя это возможно. Если бы я был вами, я бы попытался изменить ваш дизайн, чтобы вам это не понадобилось.

+1

Рекурсивная проверка действительно непростая, есть много угловых случаев, которые нужно учитывать. И это только первый шаг, следующий вам нужен эквивалент isAssignableFrom, который также обрабатывает генерики. Я бы не рекомендовал попробовать его реализовать самостоятельно. Я написал библиотеку, которая делает это для вас, называется gentyref. См. Http://code.google.com/p/gentyref/. –

0

Вы можете получить общий тип поля, в котором вы читали объект, с помощью Field.getGenericType. Обратите внимание, что поле может быть необработанным, быть редким типом (общий, но с общим аргументом, который является сырым), использовать тип экземпляра, использовать подстановочные знаки и т. Д.

0

Скопировано из моего сообщения по адресу: https://stackoverflow.com/questions/1004022/java-generic-class-determine-type/1005283#1005283

Я использовал аналогичное решение для того, что он здесь объясняет для нескольких проектов, и нашел, что это очень полезно.

http://blog.xebia.com/2009/02/07/acessing-generic-types-at-runtime-in-java/

тэки его используют следующие определения параметра типа во время выполнения:

public Class returnedClass { 
    ParameterizedType parameterizedType = 
    (ParameterizedType) getClass().getGenericSuperClass(); 
return (Class) parameterizedtype.getActualTypeArguments()[0]; 
} 
9

Вы можете абсолютно делать то, что вы хотите.Тип стирания означает, что вы не можете проверить экземпляр коллекции для своего типового типа, но вы можете, конечно, проверить поле для своего типового типа.

class Thing { 
    List<Persistable> foo; 
} 


Field f = Thing.class.getDeclaredField("foo"); 
if(Collection.class.isAssignableFrom(f.getType()) { 
    Type t = f.getGenericType(); 
    if(t instanceof ParameterizedType) { 
    Class genericType = (Class)((ParameterizedType)t).getActualTypeArguments()[0]; 
    if(Persistable.class.isAssignableFrom(genericType)) 
     return true; 
    } 
} 

Там очень много вещей, которые могут пойти не так вот, к примеру, если у вас есть

Class Thing<T> { 
    List<T> foo; 
} 

то выше, не будет работать.

+1

Я предполагаю эту строку: Класс genericType = (класс) ((ParameterizedType) t) .getActualTypeArguments [0]; должен быть Класс genericType = (класс) ((ParameterizedType) t) .getActualTypeArguments() [0]; ? – andersonbd1

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