【问题标题】:Generic Interface implementation with subclass type具有子类类型的通用接口实现
【发布时间】:2020-02-23 19:20:38
【问题描述】:

处理器接口:

public interface Processor<T> {

    public void process(T request);

    public Class<T> getRequestType();
}

处理器实现:

public class TextProcessor extends BaseProcessor implements Processor<TextRequest> {

@Override
public void process(TextRequest request) {
    // TODO Auto-generated method stub

}

@Override
public Class<TextRequest> getRequestType() {
    // TODO Auto-generated method stub
    return TextRequest.class;
}

}

请求类:

public class Request {
    private long id;

    ...
}

文本请求

public class TextRequest extends Request {
    String text;
    ...
} 

主类:

private Map<String, Processor<? extends Request>> processors;

public static void main(String[] args) {

    Processor<?> processor = processors.get("proc name");
    Request request = objectMapper.readValue(json, processor.getRequestType());

    processor.process(request);
}

我在process 调用中遇到编译错误。

The method process(capture#10-of ?) in the type Processor<capture#10-of ?> is not applicable
for the arguments (Request)

我该如何解决这个问题?

【问题讨论】:

    标签: java generics interface wildcard


    【解决方案1】:

    所以你有

    Processor<?> processor = ...;
    Request request = ...;
    processor.process(request);
    

    process 被声明为

    public void process(T request);
    

    Request 不能保证是T 的子类型,因此无法编译。

    您需要将Request 更改为正确的类型。

    首先你需要返回正确的类类型。

    public Class<?> getRequestType();
    

    变成

    public Class<T> getRequestType();
    

    编辑:现在已在原始问题中进行了修改。)

    然后我们需要读取一个正确类型的请求对象。对于任何特定对象?,此处将指代特定类型。我们可以通过引入一种新方法来捕捉到这一点。

    public static void main(String[] args) {
        doProcess(processors.get("proc name"));
    }
    private static <T> void doProcess(Processor<T> processor) {
        T request = objectMapper.readValue(json, processor.getRequestType());
        processor.process(request);
    }
    

    【讨论】:

    • process 的调用者只有处理器对象和它期望的请求类型。
    【解决方案2】:

    在编译时检查 JAVA 泛型。

    因此,当您编写 Processor&lt;?&gt; processor = processors.get("proc name"); 时,我们不知道如何针对 ? 验证请求。

    如果您可以接受 - 尝试使用非通用版本的处理器:

    Processor processor = new TextProcessor();
    

    否则可能会为Processor 接口(@98​​7654325@)添加一些约束?

    【讨论】:

    • 必须根据请求的名称动态创建实现。
    【解决方案3】:

    Processor&lt;?&gt; processor = processors.get("proc name"); 中的处理器参数化为未知类型,与processor.getRequestType() 中的类型没有任何共同之处。在这种情况下,我不清楚仿制药会给您带来什么好处。似乎您不必知道 main 函数中的具体 Request 子类型是什么,因此可以在没有泛型的情况下重写所有内容。问题的根本原因是processors 映射,其中所有处理器都在一组中。

    我可以想象泛型的好处,例如当处理器映射将被实现为异构映射时,键类型和值类型之间存在某种相关性。然后 Processor.getRequestType 也必须通过类型 T 进行参数化,然后您可以使用:

    public static void main(String[] args) {
        Processor<TextRequest> processor = processors.get(TextRequest.class);
        TextRequest request = objectMapper.readValue(json, processor.getRequestType());
        processor.process(request);
    }
    

    【讨论】:

    • 必须使用请求的名称从地图中获取处理器。处理器会告诉我它期望的请求类型。所以一切都是动态的。有没有办法使用泛型来实现这一点?
    • @cppcoder 如果您必须通过name 选择处理器(而不是我建议的其他类型感知信息),那么除了将处理器表示为通配符类型之外,您没有其他可能性。实际类型在编译时未知。然后 Tom Hawtin 的回答为您完成了这项工作 - 它使用了 Angelika Langer 在此处 angelikalanger.com/GenericsFAQ/FAQSections/… 描述的通配符技巧。简而言之,它说“无论处理器参数化的类型是什么,在辅助方法中,处理器和请求类型都必须匹配”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-23
    • 2016-02-15
    • 1970-01-01
    • 1970-01-01
    • 2022-11-28
    • 1970-01-01
    相关资源
    最近更新 更多