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

时间:2013-03-24 05:48:01

标签: java generics reflection

此类来自供应商库:

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

这些是我的模特:

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;
    }
    // ...
}

此代码有效:

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

此代码不起作用:( Response<Video>.class处的语法错误)

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

此代码有效:

public class VideoResponse extends Response<Video> {
}

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

我的问题是:如何将Response<Video>类作为参数传递给parse方法,而不像这样创建VideoResponse。 (在我的程序中,有许多类似于Video的模型,我不想复制我的代码来创建空类VideoResponseUserResponseCommentResponse,{{1} }等等)

2 个答案:

答案 0 :(得分:4)

由于Java泛型的实现方式,在大多数情况下,通用信息在运行时会丢失。这些所谓的reifiable类型的例外之一是泛型类的具体扩展。第一个例子:

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;
    }
    // ...
}

解析器无法反序列化result属性,因为它无法确定它的类型(因为此信息在运行时不可用)。基本上,解析只看到java.lang.Object,并且无法确定要实例化以将JSON数据拉入的类型。我假设您已经怀疑是这种情况,因此尝试进行此调用:

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

在上面一行中,您试图告诉解析器特定响应是使用Video参数化的,但遗憾的是Java没有泛型类文字的语法,因此代码无法编译。 / p>

在你的第二个例子中:

public class VideoResponse extends Response<Video> {
}

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

您已经创建了泛型类的具体扩展。对于此类扩展,泛型类型信息在运行时可用,因此您的解析器可以确定实例化所需的内容,以便反序列化您的JSON数据。

所有这些都是您实际问题的背景信息:

  

我的问题是:如何将Response类作为参数传递给parse方法而不创建像这样的VideoResponse

您忽略了提到您正在使用的JSON库,但在大多数流行的库中,反序列化方法都有一个覆盖版本,它接受通常所说的超类型令牌。超类型令牌基本上只是类的具体扩展,类似于我上面描述的。例如,在杰克逊,您可以像这样反序列化您的JSON:

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

您应该检查JSON库文档中的类似内容。

答案 1 :(得分:0)

由于Java泛型类型的“类型擦除”,您应该明确使用类型转换,如下所示:

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

它会引入编译警告,但没关系。