使用反射在运行时推断java泛型参数

时间:2010-12-09 14:58:23

标签: java generics reflection

我有一个带有以下签名的方法:

// Converts a json string to a list of objects
// Assumption: json is an array, and all items in the list are of the same type
public <T> List<T> getListFromJson( String json, Class<T> itemType, List<T> defValue ) {
    final ArrayList<T> list = new ArrayList<T>();

    for( JsonElement e : parser.parse(json).getAsJsonArray())
        list.add( (T) (
                Number.class.isAssignableFrom(itemType) ? e.getAsNumber() :
                Boolean.class.isAssignableFrom(itemType) ? e.getAsBoolean() :
                Character.class.isAssignableFrom(itemType) ? e.getAsCharacter() :
                String.class.isAssignableFrom(itemType) ? e.getAsString() :
                JsonElement.class.isAssignableFrom(itemType) ? e :
                null
            )
        );

    return list;
}

它读取json字符串并将其转换为适当类型对象的列表,例如。整数,字符串等

是否有一种强大的方法可以通过从Class<T>参数推断出方法来从方法中删除List<T>参数?例如。有没有办法可以在不丢失功能的情况下将方法签名更改为以下内容?

public <T> List<T> getListFromJson( String json, List<T> defValue ) {
    ...
}

似乎解决方案需要对ParameterizedType进行一些奇特的操作。我看过以下内容,但要么我使用这些方法不正确,要么他们没有做我期望的事情:

2 个答案:

答案 0 :(得分:7)

由于type erasure,你绝对无法“推断”T是什么 - 它甚至在运行时都不存在。你最接近的是检查defValue中的值(如果它有值)并获取那里的元素类。

Class<?> tType = defValue.get(0).getClass();

if (Boolean.class.isAssignableFrom(tType)) { //...  

修改

关于您使用getTypeArguments()等反射的想法,这些只为声明的类型提供数据,而不是实际的类型。例如,如果你有Method对象的句柄并调用getTypeParameters(),你只需要一个包含表示T的类型对象的数组 - 而不是T的实际类型。 {1}}代表某些特定的运行时调用。

答案 1 :(得分:1)

我知道保证在运行时访问该类型的唯一方法是使其成为对象构造函数的参数:

class MyClass<T> {
    private final Class<T> clazz;
    public MyClass(Class<T> clazz) {
        this.clazz=clazz;
    }
}

然后,在实例化对象时必须传递该类:

MyClass<String> object = new MyClass<String>(String.class);

显然,在你的情况下,你有一个有效的静态实用方法而没有对象,所以我认为你坚持使用Class参数或者某种模板对象。