在 Java 中将带有类型参数的类作为泛型方法的类型参数传递

2022-08-31 17:02:18

问题摘要:我想将带有类型参数的类(例如,)作为类型参数传递给泛型方法。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

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

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


答案 1

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

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

这是相当麻烦的。为了简化我们的生活,谷歌已经为我们编写了代码中大部分无聊的部分,并通过Guava提供了它。

检查 TypeToken 类,该类完全符合您的要求。例如:

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

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

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

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


答案 2