问题摘要:
我想将一个带有类型参数的类(例如ArrayList<SomeClass>
)作为类型参数传递给泛型方法。
假设我有一个方法:
public static <T> T getGenericObjectFromJson(String json, Class<T> genericType){
// details unimportant, basically returns an object of specified type
return JsonParser.fromJson(json, genericType);
}
当然,这种方法对于任何类别都可以完美地运行。我可以像这样调用方法,例如:
getGenericObjectFromJson(jsonString, User.class)
问题:我发现我不能这样做:
getGenericObjectFromJson(jsonString, ArrayList<User>.class)
从语法上讲,这显然是无效的。但是,我不确定我是如何做到这样的。当然,我可以传递ArrayList.class
,但是通用类型的添加使它不再具有语法上的有效性,我无法想到解决它的方法。
唯一直接的解决方案就是这样(看起来很傻):
getGenericObjectFromJson(jsonString, new ArrayList<User>().getClass())
然而,我们最终失去了泛型类型,并且只返回一个未知类型的ArrayList(尽管它可以被强制转换)。另外,不必要地实例化对象。
到目前为止,我唯一的解决方案是将该方法包装在一个包含可以实例化的泛型类型参数的类中,如下所示:
public class JsonDeserializer<T>...
在这种情况下,getGenericObjectFromJson
方法将使用类的泛型类型。
问题:最后,我很好奇为什么我不能传递一个带有类型参数的类,以及是否有办法完成我试图做的事情。
与往常一样,如果此问题存在任何问题,请与我联系。
答案 0 :(得分:59)
这实际上可以在Java中使用一些“技巧”。不要屈服于C#狂热分子的压力! (J / K)
“技巧”是创建一个扩展泛型类型的类,并通过Type
或.getGenericSuperclass()
返回的.getGenericInterfaces()
访问父类的type参数的值
这非常麻烦。为了简化我们的生活,Google已经为我们编写了大部分无聊的代码部分,并通过Guava提供。
检查 TypeToken
类,它完全符合您的要求。例如:
TypeToken<List<String>> stringListTok = new TypeToken<List<String>>() {};
然后你绕过TypeToken<T>
而不是Class<T>
,这就是全部。它为您提供了对T表示的类型进行反射的方法。
这在内部执行的操作只是调用.getClass().getGenericSuperclass()
(或...Interfaces()
),然后从Type
调用ParameterizedType
到.getActualTypeArguments()
并从中检索所有信息({ {1}}等。)
最后,如果你想用Dependency Injection做类似的事情(也就是说,假设你需要在类的构造函数上注入Class<T>
,或者你想得到一个参数化接口的实例,其中实例应该取决于类型参数),Google Guice(来自Google的DI容器)有一个非常类似的机制来解决问题,称为TypeLiteral
。幕后使用和代码几乎与Guava的TypeToken
相同。请在此处查看: TypeLiteral