在运行时指定泛型集合类型参数(Java Reflection)

时间:2009-07-14 20:45:04

标签: 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中获取集合的泛型类型?在我的情况下,我需要集合的泛型类型的.class。

提前致谢!

4 个答案:

答案 0 :(得分:17)

Type erasure表示有关对象的泛型类型的信息在执行时不存在。

(链接指向Angelika Langer 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 :(得分: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;
}

然后上面的内容将无效。

答案 2 :(得分:0)

您可以使用Field.getGenericType获取您从中读取对象的字段的泛型类型。请注意,该字段可能是原始类型,是一种罕见的类型(通用但具有原始的泛型参数),使用实例的类型,使用通配符等。

答案 3 :(得分: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];
}