Java 具有另一个泛型类作为参数的泛型类

Java 具有另一个泛型类作为参数的泛型类,java,generics,nested-generics,Java,Generics,Nested Generics,我发现自己在使用泛型时遇到了一种奇怪的情况,到目前为止,这似乎是不可能的。我试着在简单的课堂上孤立这种情况。我试图实现的是:一个分派句柄以处理数据包的服务类。每个处理程序都有一个数据包类型参数,因为每个数据包都应该有一个处理程序。服务类还有一个Handler type参数,因为有几种类型的处理程序,所以不同的处理程序类型需要几种服务。这个描述可能不是很清楚,所以我举了一个例子: public abstract class Service<T extends Handler<?>

我发现自己在使用泛型时遇到了一种奇怪的情况,到目前为止,这似乎是不可能的。我试着在简单的课堂上孤立这种情况。我试图实现的是:一个分派句柄以处理数据包的服务类。每个处理程序都有一个数据包类型参数,因为每个数据包都应该有一个处理程序。服务类还有一个Handler type参数,因为有几种类型的处理程序,所以不同的处理程序类型需要几种服务。这个描述可能不是很清楚,所以我举了一个例子:

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 {

}
公共抽象类服务>{
@凌驾
受保护的无效句柄(HandlerOne句柄,E数据包){
handle.handle(“someString”,数据包);//错误
}
}
公共接口处理程序{
}
公共接口HandlerOne扩展处理程序{
无效句柄(objectsomeobject,E数据包);
}
公共类HandlerOneImpl实现HandlerOne{
@凌驾
公共无效句柄(对象someObject,SomePacket){
}
}
公共接口包{
}
公共类SomePacket实现数据包{
}
有没有办法完成这样的事情,或者有什么建议?谢谢

编辑:这是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);
    }

}
publicstaticvoidmain(字符串[]args){
HashMap>s=newServiceImpl(handlerMap);//错误
}
公共静态抽象类服务{

Map方法
句柄
需要一个
对象
和一个类型为
E
的参数(类型参数)。您只指定了第二个

然后,由于
通配符的捕获转换,即使在第一个参数中引入
对象
,仍然会出现错误。因此,我将使用两个类型参数:

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
    }
}
公共抽象类服务{
//一些随机逻辑
受保护的抽象无效句柄(T句柄、E包);
}
公共类ServiceImpl扩展了服务{
@凌驾
受保护的无效句柄(T处理程序、E数据包){
handle.handle(new Object(),packet);//将某个对象作为第一个参数
}
}
当前代码的问题在于以下语句:

protected <E extends Packet> void handle(HandlerOne<?> handler, E packet) {
    handler.handle("someString", packet); //ERROR
}
受保护的无效句柄(HandlerOne句柄,E数据包){
handle.handle(“someString”,数据包);//错误
}

您正在告诉处理程序,该处理程序被键入“some”数据包类型,用于处理
E
类型的数据包。在运行时,处理程序的实际数据包类型可能不是
E

您遇到了Java类型系统的限制,要正确地做到这一点,您需要类似的东西。Java不支持这一点,我见过的最接近实现的是(实验性)项目。HighJ使用见证类型来分离容器和值类型。例如,从它们的

我发现在Java中模拟高阶类型多态性的唯一方法是使用我们已有的抽象,即类型参数的抽象。要做到这一点,我们需要将“容器类型”从其值类型中分离出来,然后将其本身作为类型参数。所以

列表我们有类似
某物
但是,在生产(Java)项目上这样做可能不是一个好主意,因为它很复杂,学习曲线很陡。我建议您在某个地方简化设计

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

   List<T extends Processor<E>> 
列表
例如),为了使设计更简单,您可以牺牲抽象(在某处复制一些代码),也可以牺牲类型安全(动态语言与具有高级类型系统的语言一样简洁)


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

我看到的第一件事是:您试图调用句柄,期望两个参数只给出一个。@Jean-FrançoisSavard Oops,是的,我的错。这是一个错误,但我无法找出的主要错误是让服务中的处理程序和数据包对齐。是否有多个不同的类型添加到HashMap中,然后传递给ServiceImpl?因为看起来您试图让该类在内部处理多个类型,但只提供一个(更高级的类型)外部类型视图?@JohnMcClean是的,这就是我试图实现的。你能解释一下原因吗?因为如果服务实际上处理多个类型,它没有一个类型可以公开。删除高阶泛型会使事情变得更简单吗?例如类服务?我认为没有一个类型e或t包含数据包和手是的。我尝试了一些类似的方法,现在已经接近解决方案了,但它引入了另一个问题。ServiceImpl类必须处理HandlerOne的几个实现,所有这些实现都有不同的数据包实现参数。我想这将使创建新的ServiceImpl成为不可能。@stripes I d我不知道这将如何阻止它处理不同的
HandlerOne
实现。您能提供一个问题示例吗?
   List<T extends Processor<E>>