【问题标题】:Specifying generic collection type param at runtime (Java Reflection)在运行时指定泛型集合类型参数(Java 反射)
【发布时间】:2012-10-05 02:43:22
【问题描述】:

我想在运行时使用反射获取集合的泛型类型。

代码(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。

提前致谢!

【问题讨论】:

标签: java reflection


【解决方案1】:

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&lt;T&gt;,那么您必须知道实例的类型参数才能知道集合的类型参数。

不过,将其转换为您所需的代码有些棘手 - 您确实需要知道集合类的类型参数。例如,如果有人声明:

public class StringCollection implements Collection<String>

然后有一个StringCollection 类型的字段,该字段本身不会有任何类型参数。然后,您需要递归检查getGenericSuperTypegetGenericInterfaces,直到找到您想要的。

尽管有可能,但要做到这一点确实不容易。如果我是你,我会尝试改变你的设计,这样你就不需要这个了。

【讨论】:

  • 递归检查确实不容易,有很多极端情况需要考虑。这只是第一步,接下来你需要一个 isAssignableFrom 等价物来处理泛型。我不建议尝试自己实现它。我为您编写了一个库,称为 gentyref。见code.google.com/p/gentyref
【解决方案2】:

你绝对可以做你想做的事。类型擦除意味着您无法检查集合的实例的泛型类型,但您当然可以检查字段的泛型类型。

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;
}

那么上面的就行不通了。

【讨论】:

  • 我猜这一行: Class genericType = (Class)((ParameterizedType)t).getActualTypeArguments[0];应该是 Class genericType = (Class)((ParameterizedType)t).getActualTypeArguments()[0]; ?
【解决方案3】:

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

【讨论】:

    【解决方案4】:

    复制自我的帖子: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];
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-25
      • 2021-05-03
      • 1970-01-01
      • 2015-03-18
      • 1970-01-01
      • 2023-03-14
      相关资源
      最近更新 更多