简体   繁体   English

将参数化类型作为参数传递给方法

[英]Pass parameterized type to method as argument

This class is from vendor library: 该类来自供应商库:

public class JsonParser {
    public <T> T parse(String json, Class<T> type) { ... }
}

These are my models: 这些是我的模特:

public class Video {
    @Key
    private String title;
    public String getTitle() {
        return title;
    }
}

public class Response<TResult> {
    @Key
    private TResult result;
    public TResult getResult() {
        return result;
    }
    // ...
}

This code works: 此代码有效:

JsonParser parser = new JsonParser();
String json = "{ \"title\": \"Hello world\" }";
Video video = parser.parse(json, Video.class);

This code doesn't work: (syntax error at Response<Video>.class ) 此代码不起作用:( Response<Video>.class语法错误)

JsonParser parser = new JsonParser();
String json = "{ \"result\" : { \"title\": \"Hello world\" } }";
Response<Video> videoResponse = parser.parse(reader, Response<Video>.class);

This code works: 此代码有效:

public class VideoResponse extends Response<Video> {
}

...
JsonParser parser = new JsonParser();
String json = "{ \"result\" : { \"title\": \"Hello world\" } }";
Response<Video> videoResponse = parser.parse(reader, VideoResponse.class);

My question is: How to pass Response<Video> class to parse method as parameter without creating VideoResponse like that. 我的问题是:如何将Response<Video>类传递给parse方法作为参数而不创建像这样的VideoResponse (In my program, there are many models similar to Video , I dont want to duplicate my code to create empty classes VideoResponse , UserResponse , CommentResponse , ActivityResponse , etc) (在我的节目,也有类似的许多型号Video ,我不想重复我的代码创建空类VideoResponseUserResponseCommentResponseActivityResponse等)

Because of the way Java generics are implemented, in most cases the generic information is lost at runtime. 由于Java泛型的实现方式,在大多数情况下,通用信息在运行时会丢失。 One of the exceptions to these so-called reifiable types are concrete extensions of generic classes. 这些所谓的可再生类型的例外之一是泛型类的具体扩展。 For your first example: 第一个例子:

public class Video {
    @Key
    private String title;
    public String getTitle() {
        return title;
    }
}

public class Response<TResult> {
    @Key
    private TResult result;
    public TResult getResult() {
        return result;
    }
    // ...
}

The parser would not be able to deserialize the result property because it would be unable to determine what type it is (since this information is not available at runtime). 解析器无法反序列化result属性,因为它无法确定它的类型(因为此信息在运行时不可用)。 Basically, the parse just sees java.lang.Object , and cannot determine the type to instantiate to pull the JSON data into. 基本上,解析只是看到java.lang.Object ,并且无法确定要实例化以将JSON数据拉入的类型。 I assume you already suspect this to be the case, hence the attempt to make this call: 我假设您已经怀疑是这种情况,因此尝试进行此调用:

Response<Video> videoResponse = parser.parse(reader, Response<Video>.class);

In the above line you are attempting to tell the parser that the particular response is parameterized with Video , but unfortunately Java doesn't have a syntax for generic class literals, so the code doesn't compile. 在上面的行中,您试图告诉解析器特定响应是使用Video参数化的,但遗憾的是Java没有泛型类文字的语法,因此代码无法编译。

In your second example: 在你的第二个例子中:

public class VideoResponse extends Response<Video> {
}

Response<Video> videoResponse = parser.parse(reader, VideoResponse.class);

You've created a concrete extension of your generic class. 您已经创建了泛型类的具体扩展。 For such extensions, the generic type information is available at runtime, so your parser can determine what it needs to instantiate in order to deserialize your JSON data. 对于此类扩展,泛型类型信息在运行时可用,因此您的解析器可以确定实例化所需的内容以反序列化您的JSON数据。

All this is background information to your actual question: 所有这些都是您实际问题的背景信息:

My question is: How to pass Response class to parse method as parameter without creating VideoResponse like that 我的问题是:如何将Response类作为参数传递给parse方法而不创建像这样的VideoResponse

You neglected to mention what JSON library you are using, but in most of the popular libraries the deserialize methods have an overriden version that accepts what is commonly called a super type token . 你忽略了你正在使用的JSON库,但是在大多数流行的库中,反序列化方法都有一个覆盖版本,它接受通常所说的超类型令牌 A super type token is basically just a concrete extension of a class, similar to what I described above. 超类型令牌基本上只是类的具体扩展,类似于我上面描述的。 In Jackson, for example, you would deserialize your JSON like this: 例如,在Jackson中,您可以像这样反序列化您的JSON:

Response<Video> response = new ObjectMapper().readValue(
    jsonString, // JSON data
    new TypeReference<Response<Video>>() {} // super type token, implemented by anonymous class
);

You should check your JSON libraries documentation for anything similar. 您应该检查您的JSON库文档中的类似内容。

Due to "type erasure" of Java generic types, you should use type cast explicitly as following instead: 由于Java泛型类型的“类型擦除”,您应该明确使用类型转换,如下所示:

Response<Video> videoResponse = (Response<Video>) parser.parse(reader, Response.class);

It will introduce a compilation warning but it's okay. 它会引入编译警告,但没关系。

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

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