58

问题总结: 我想将一个带有类型参数的类(例如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方法将使用类的泛型类型。

问题:最终,我很好奇为什么我不能传递带有类型参数的类,以及是否有办法完成我试图做的事情。

与往常一样,如果这个问题有任何问题,请告诉我。

4

1 回答 1

67

这在 Java 中实际上是可能的,使用一些“技巧”。不要屈服于 C# 狂热分子的压力!(j/k)

Type“诀窍”是创建一个扩展泛型类型的类,并通过返回的.getGenericSuperclass()or访问父类的类型参数的值.getGenericInterfaces()

这是相当麻烦的。为了简化我们的生活,Google 已经为我们编写了大部分枯燥的代码,并通过 Guava 提供。

检查TypeToken类,这正是你想要的。例如:

TypeToken<List<String>> stringListTok = new TypeToken<List<String>>() {};

然后你传递 aTypeToken<T>而不是 a Class<T>,仅此而已。它为您提供了对 T 表示的类型进行反射的方法。

这在内部所做的只是简单地调用.getClass().getGenericSuperclass()(或),然后从to...Interfaces()进行一些丑陋的转换并从那里检索所有信息(等)。TypeParameterizedType.getActualTypeArguments()

最后,如果你想用依赖注入做类似的事情(即假设你需要Class<T>在一个类的构造函数上注入a,或者你想获得某个参数化接口的实例,其中的实例应该依赖于类型参数),Google Guice(来自 Google 的 DI 容器)有一个非常相似的机制来解决这个问题,称为TypeLiteral. 后台的使用和代码几乎与TypeTokenGuava 相同。在这里检查:TypeLiteral

于 2013-08-27T17:23:43.167 回答