传递带有类型参数的类作为 Java 中泛型方法的类型参数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18471701/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Passing a class with type parameter as type parameter for generic method in Java
提问by Paul Richter
Problem summary:I would like to pass a class with a type parameter (such as ArrayList<SomeClass>
, for example) to a generic method as a type parameter.
问题摘要:我想将带有类型参数(ArrayList<SomeClass>
例如 )的类作为类型参数传递给泛型方法。
Let's say I have a method:
假设我有一个方法:
public static <T> T getGenericObjectFromJson(String json, Class<T> genericType){
// details unimportant, basically returns an object of specified type
return JsonParser.fromJson(json, genericType);
}
This method, of course, will work perfectly fine for any kind of class. I can call the method like so, for example:
当然,这种方法对于任何类型的类都可以很好地工作。我可以像这样调用方法,例如:
getGenericObjectFromJson(jsonString, User.class)
The problem:I discovered I cannot do this:
问题:我发现我不能这样做:
getGenericObjectFromJson(jsonString, ArrayList<User>.class)
Syntactically, this is obviously invalid. However, I am not certain how I would even accomplish something like this. I can, of course, pass ArrayList.class
, however the addition of the generic type makes it no longer syntactically valid, and I cannot think of a way around it.
从语法上讲,这显然是无效的。但是,我不确定我将如何完成这样的事情。我当然可以 pass ArrayList.class
,但是泛型类型的添加使它在语法上不再有效,我想不出解决方法。
The only direct solution has been something like this (which seems rather goofy):
唯一的直接解决方案是这样的(这看起来相当愚蠢):
getGenericObjectFromJson(jsonString, new ArrayList<User>().getClass())
However we end up losing the generic type anyways, and merely get back an ArrayList of unknown type (though it can be cast). Plus, unnecessarily instantiating an object.
然而,无论如何我们最终都会丢失泛型类型,并且只会返回一个未知类型的 ArrayList(尽管它可以被强制转换)。另外,不必要地实例化一个对象。
My only solution thus far has been to wrap that method in a class that contains a generic type parameter which can be instantiated, like so:
到目前为止,我唯一的解决方案是将该方法包装在一个包含可以实例化的泛型类型参数的类中,如下所示:
public class JsonDeserializer<T>...
In this case, the getGenericObjectFromJson
method will use the class's generic type.
在这种情况下,该getGenericObjectFromJson
方法将使用类的泛型类型。
The Question(s):Ultimately, I am curious why I cannot pass a class with a type parameter, AND whether there is a way to accomplish what I attempted to do.
问题:最终,我很好奇为什么我不能传递带有类型参数的类,以及是否有办法完成我尝试做的事情。
As always, let me know if there are any problems with this question.
与往常一样,如果这个问题有任何问题,请告诉我。
采纳答案by Bruno Reis
This is actually possible in Java, using some "tricks". Don't succumb to pressure from the C# fanatics! (j/k)
这在 Java 中实际上是可能的,使用一些“技巧”。不要屈服于 C# 狂热者的压力!(j/k)
The "trick" is to create a class that extends a generic type, and access the value of the type parameter of the parent class through the Type
returned by .getGenericSuperclass()
or .getGenericInterfaces()
.
“诀窍”是创建一个扩展泛型类型的类,并通过Type
返回的.getGenericSuperclass()
或访问父类的类型参数的值.getGenericInterfaces()
。
This is quite cumbersome. To simplify our lives, Google has already written most of the boring part of the code for us, and made it available through Guava.
这是相当麻烦的。为了简化我们的生活,Google 已经为我们编写了大部分无聊的代码部分,并通过 Guava 提供。
Check the TypeToken
class, which does exactly what you want. For example:
检查TypeToken
课程,这正是您想要的。例如:
TypeToken<List<String>> stringListTok = new TypeToken<List<String>>() {};
Then you pass around a TypeToken<T>
instead of a Class<T>
and that's all. It provides you with methods to do reflection on the type represented by T.
然后你传递 aTypeToken<T>
而不是 a Class<T>
,仅此而已。它为您提供了对 T 表示的类型进行反射的方法。
What this is doing internally is simply calling .getClass().getGenericSuperclass()
(or ...Interfaces()
), then some ugly casts from Type
to ParameterizedType
and retrieving all the information from there (.getActualTypeArguments()
, etc).
这在内部所做的只是简单地调用.getClass().getGenericSuperclass()
(或...Interfaces()
),然后从Type
to进行一些丑陋的转换ParameterizedType
并从那里检索所有信息(.getActualTypeArguments()
等)。
Finally, if you want to do something similar with Dependency Injection (ie, suppose you need to inject a Class<T>
on the constructor of a class, or you want to get an instance of some parameterized interface, in which the instance should depend on the type parameter), Google Guice (a DI container from Google) has a very similar mechanism to solve the problem, called TypeLiteral
. The use and the code behind the scenes are almost identical to TypeToken
from Guava. Check it here: TypeLiteral
最后,如果你想用依赖注入做类似的事情(即假设你需要Class<T>
在类的构造函数上注入一个,或者你想获得某个参数化接口的实例,其中该实例应该依赖于类型参数),Google Guice(来自 Google 的 DI 容器)有一个非常相似的机制来解决这个问题,称为TypeLiteral
. 幕后的使用和代码几乎与TypeToken
来自 Guava 的相同。在这里检查:TypeLiteral