4

我发现自己在使用泛型时遇到了一种奇怪的情况,到目前为止这似乎是不可能的。我尝试在简单的类中隔离这种情况。我试图完成的是:一个调度句柄来处理数据包的服务类。每个处理程序都有一个数据包类型参数,因为每个数据包都应该有一个处理程序。服务类也有一个 Handler 类型参数,因为有几种类型的处理程序,因此不同的处理程序类型需要几个服务。这个描述可能不是很清楚,所以这里是我做的例子:

public abstract class Service<T extends Handler<?>> {

    //Some random logic

    //If only I could use T<E>
    protected abstract <E extends Packet> void handle(T handler, E packet);

}

public class ServiceImpl extends Service<HandlerOne<?>> {

    @Override
    protected <E extends Packet> void handle(HandlerOne<?> handler, E packet) {
        handler.handle("someString", packet); //ERROR
    }

}

public interface Handler<E extends Packet> {

}

public interface HandlerOne<E extends Packet> extends Handler<E> {

    void handle(Object someObject, E packet);

}

public class HandlerOneImpl implements HandlerOne<SomePacket> {

    @Override
    public void handle(Object someObject, SomePacket packet) {
    }

}

public interface Packet {

}

public class SomePacket implements Packet {

}

有没有办法完成这样的事情,或者有什么建议?谢谢

编辑:这是来自 manouti 答案的修改后的代码(注意:为了清楚起见,我将 SomePacket 更改为 PacketOne)。我遇到的问题是创建 ServiceImpl 的实例。

public static void main(String[] args) {
    HashMap<Class<? extends Packet>, HandlerOne<? extends Packet>> handlerMap = new HashMap<>();
    handlerMap.put(PacketOne.class, new HandlerOneImpl());

    ServiceImpl<Packet, HandlerOne<?>> s = new ServiceImpl<>(handlerMap);//ERROR
}

public static abstract class Service<E extends Packet, T extends Handler<E>> {

    Map<Class<? extends Packet>, T> handlerMap;

    public Service(Map<Class<? extends Packet>, T> handlerMap) {
        this.handlerMap = handlerMap;
    }

    //Some random logic

    //If only I could use T<E>
    protected abstract void handle(T handler, E packet);

}

public static class ServiceImpl<E extends Packet, T extends HandlerOne<E>> extends Service<E, T> {

    public ServiceImpl(Map<Class<? extends Packet>, T> handlerMap) {
        super(handlerMap);
    }

    @Override
    protected void handle(T handler, E packet) {
        handler.handle("someObject", packet);
    }

}
4

2 回答 2

3

该方法handle需要一个ObjectE类型的参数(类型参数)。您只指定了第二个。

Object那么,由于?通配符的捕获转换,即使您在第一个参数中引入 an,您仍然会收到错误。所以我会使用两个类型参数:

public abstract class Service<E extends Packet, T extends Handler<E>> {
    // Some random logic

    protected abstract void handle(T handler, E packet);

}

public class ServiceImpl<E extends Packet, T extends HandlerOne<E>> extends Service<E, T> {
    @Override
    protected void handle(T handler, E packet) {
        handler.handle(new Object(), packet); // some object as first parameter
    }
}

当前代码的问题在于以下语句:

protected <E extends Packet> void handle(HandlerOne<?> handler, E packet) {
    handler.handle("someString", packet); //ERROR
}

您是在告诉处理程序,它被键入为“某些”数据包类型,来处理类型为 的数据包E。在运行时,处理程序的实际数据包类型可能不是E.

于 2015-09-21T20:04:47.590 回答
0

您遇到了 Java 类型系统的限制,要正确执行此操作,您需要类似Higher Kinded Types的东西。Java 不支持这一点,我见过的最接近实现的是(实验)项目HighJ中的类型。HighJ 使用见证类型来分隔容器和值类型。例如来自他们的wiki

我发现在 Java 中模拟高阶类型多态性的唯一方法是使用我们已经拥有的抽象,即类型参数的抽象。为此,我们需要将“容器类型”与其值类型分开,然后使其本身成为类型参数。所以而不是

   List<String> we have something like 
   Something<List, String>.

但是,在生产 (Java) 项目中执行此操作可能不是一个好主意,因为它很复杂并且学习曲线陡峭。我建议你在某个地方让你的设计更简单。

更高种类的类型(泛型上的泛型)允许更高级别的抽象(你可以说

   List<T extends Processor<E>> 

例如),并且为了使您的设计更简单,您可以牺牲抽象(在某处复制一些代码)或类型安全(动态语言与具有高级类型系统的语言一样简洁)。

您可以通过额外的单元测试来弥补类型安全的损失。

于 2015-09-21T20:33:19.557 回答