2009-07-14 66 views
5

我想在运行时使用反射来获取集合的通用类型。在运行时指定通用集合类型参数(Java反射)

代码(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中的一种方式?在我的情况下,我需要该集合的泛型类型的.class。

在此先感谢!

+0

我正面临着类似的问题,这终于为我解决了这个问题:http://stackoverflow.com/a/183232/639119 – Zds 2012-10-04 18:43:22

回答

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类型的字段,该字段本身不会有任何类型的参数。然后你需要递归地检查getGenericSuperTypegetGenericInterfaces,直到找到你想要的。

虽然这是可能的,但确实不会那么容易。如果我是你,我会尝试改变你的设计,这样你就不需要这个。

+1

递归检查确实不容易,有很多案例需要考虑。这只是第一步,接下来你需要一个isAssignableFrom等价物来处理泛型。我不会推荐尝试自己实现它。我写了一个为你做这个的库,叫做gentyref。请参阅http://code.google.com/p/gentyref/。 – 2010-06-08 21:28:12

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/

它的JIST使用以下,以确定在运行时类型参数:

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

我猜这条线: Class genericType =(Class)((ParameterizedType)t).getActualTypeArguments [0]; 应该是 类genericType =(Class)((ParameterizedType)t).getActualTypeArguments()[0]; ? – andersonbd1 2009-12-15 15:55:50