简体   繁体   English

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

[英]Passing a class with type parameter as type parameter for generic method in Java

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. 当然,我可以传递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). 但是我们最终会丢失泛型类型,并且只返回一个未知类型的ArrayList(尽管它可以被强制转换)。 Plus, unnecessarily instantiating an object. 另外,不必要地实例化对象。

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. 一如既往,请告诉我这个问题是否有任何问题。

This is actually possible in Java, using some "tricks". 这实际上可以在Java中使用一些“技巧”。 Don't succumb to pressure from the C# fanatics! 不要屈服于C#狂热分子的压力! (j/k) (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() . “技巧”是创建一个扩展泛型类型的类,并通过.getGenericSuperclass().getGenericInterfaces()返回的Type访问父类的type参数的值。

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. 检查TypeToken类,它完全符合您的要求。 For example: 例如:

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

Then you pass around a TypeToken<T> instead of a Class<T> and that's all. 然后你传递一个TypeToken<T>而不是Class<T> ,这就是全部。 It provides you with methods to do reflection on the type represented by 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转换为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 . 最后,如果你想用Dependency Injection做类似的事情(也就是说,假设你需要在Class<T>的构造函数上注入一个Class<T> ,或者你想获得一个参数化接口的实例,其中实例应该依赖在类型参数上),Google Guice(来自Google的DI容器)有一个非常类似的机制来解决这个问题,称为TypeLiteral The use and the code behind the scenes are almost identical to TypeToken from Guava. 幕后的使用和代码几乎与Guava的TypeToken完全相同。 Check it here: TypeLiteral 在这里查看: TypeLiteral

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM