如何使用Reflection来检查对象的泛型类型?

时间:2012-04-26 16:34:15

标签: java generics reflection

我需要检查一个类的字段是否为List<String>。我尝试使用以下代码执行此操作:

for (Field formField : formClass.getDeclaredFields()) {    
  ...
  if (formField.getGenericType().equals((Class<List<String>>)(Class<?>)List.class)) {
    ...
  }
}

这似乎是错误的代码,因为即使在实际为formField.getGenericType().equals((Class<List<String>>)(Class<?>)List.class)的字段上,false也会返回List<String>

另一种方法是首先测试一个字段是否为List formField.getType().equals(List.class),然后检查它是否与formField.getGenericType() instanceof ParameterizedType一致,最后检查类型参数的类。

但我认为实施此检查的方法较短。有吗?

2 个答案:

答案 0 :(得分:4)

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

public class Main {
    private List<String> strings;
    private List<ReflectionUtils> list;
    public static void main(String[] args) {
        List<Class> genericTypes = ReflectionUtils.getGenericType(Main.class);
        for(Class genericType : genericTypes) {
            System.out.println(genericType.getName());
        }
    }
}

class ReflectionUtils {
    public static List<Class> getGenericType(Class clazz) {
        List<Class> genericTypes = new ArrayList<Class>();
        Field[] fields = clazz.getDeclaredFields();
        for(Field field : fields) {
            Class c = getGenericType(field);
            if(c != null) {
                genericTypes.add(c);
            }
        }
        return genericTypes;
    }

    public static Class getGenericType(Field field) {
        Type genericType = field.getGenericType();
        if(genericType instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) genericType;
            return (Class) parameterizedType.getActualTypeArguments()[0];
        }
        return null;
    }
}

示例输出:

java.lang.String
ReflectionUtils

答案 1 :(得分:3)

您可以使用Guava的新TypeToken类(将包含在12.0版本中......它的发布候选版本目前在Maven中可用),如下所示:

for (Field formField : formClass.getDeclaredFields()) {    
  ...
  TypeToken<?> type = TypeToken.of(formField.getGenericType());
  if (type.equals(new TypeToken<List<String>>(){}) {
    ...
  }
}

请注意,这仅在类字段实际声明为List<String>而非List<T>ArrayList<String>时才有效。如果您希望它与ArrayList<String>或实现List<String>的任何其他类型匹配,则可以执行以下检查:

if (new TypeToken<List<String>>(){}.isAssignableFrom(type)) {

实际上可以找出在声明课程中声明为List<String>的{​​{1}}字段,前提是您正在处理的课程是子类,在其类型中指定List<T>是什么。举个例子:

T

有关class Foo<T> { private List<T> list; ... } class StringFoo extends Foo<String> { // T is specified in here ... } TypeToken<StringFoo> stringFooType = TypeToken.of(StringFoo.class); // iterate through superclasses of StringFoo for (TypeToken<?> superclass : stringFooType.getTypes().classes()) { for (Field field : superclass.getRawType().getDeclaredFields()) { // actually resolves T to String for the List<T> field using info from // StringFoo's type TypeToken<?> type = stringFooType.resolveType(field.getGenericType()); if (new TypeToken<List<String>>(){}.isAssignableFrom(type)) { System.out.println("List<String> found!"); } } } 可用here的详细信息。