java泛型声明需要派生类

java泛型声明需要派生类,java,generics,abstraction,Java,Generics,Abstraction,我遇到了一个棘手的问题,似乎用java泛型无法解决。这有点复杂,但我想不出一个更简单的场景来说明这个问题。。。下面是: 我有一个需要上下文的处理器类。有不同类型的语境;大多数处理器只需要任何抽象上下文,而其他处理器则需要特定的子类。像这样: abstract class AbstractProcessor<C extends Context> { public abstract void process(C context); } class BasicProcessor

我遇到了一个棘手的问题,似乎用java泛型无法解决。这有点复杂,但我想不出一个更简单的场景来说明这个问题。。。下面是:

我有一个需要上下文的处理器类。有不同类型的语境;大多数处理器只需要任何抽象上下文,而其他处理器则需要特定的子类。像这样:

abstract class AbstractProcessor<C extends Context> {
    public abstract void process(C context);
}

class BasicProcessor extends AbstractProcessor<Context> {
    @Override
    public void process(Context context) {
        // ... //
    }
}

class SpecificProcessor extends AbstractProcessor<SpecificContext> {
    @Override
    public void process(SpecificContext context) {
        // ... //
    }
}
抽象类抽象处理器{
公共抽象无效过程(C语境);
}
类BasicProcessor扩展了AbstractProcessor{
@凌驾
公共作废流程(上下文){
// ... //
}
}
类SpecificProcessor扩展了AbstractProcessor{
@凌驾
公共作废流程(特定上下文){
// ... //
}
}
好的,很酷:处理器可以声明他们需要的上下文类型,并且可以假定正确的类型将在不强制转换的情况下传递到process()中

现在,我有一个Dispatcher类,它拥有字符串到处理器的映射:

class Dispatcher<C extends Context> {
    Map<String, AbstractProcessor<? super C>> processorMap = new HashMap<String, AbstractProcessor<? super C>>();

    public void registerProcessor(String name, AbstractProcessor<? super C> processor) {
        processorMap.put(name, processor);
    }

    public void dispatch(String name, C context) {
        processorMap.get(name).process(context);
    }
}
类调度器{

Map听起来您的问题是需要泛型引用子类的特定确切类型,而不是从父类继承泛型定义。请尝试将上下文类定义为

class Context<C extends Context<C>>
子类可以避免这种情况,因为它们在定义中包含递归性:

class SpecificContext extends Context<SpecificContext>
类特定上下文扩展上下文
我认为这从根本上就是问题所在-编译器无法保证
C
Context
是相同的类型,因为它没有必要的特殊大小写逻辑来确定这两个类型实际上是等效的类型(实际上,只有当wilcard链接是无限的时候才可能发生这种情况,因为在任何非无限的意义上,扩展后的wilcard链接总是比第一个链接更深一层)

因此,这不是一个很好的结论,但我认为在这种情况下需要您的强制转换,因为编译器无法为自己导出等价性。或者,如果您在类似位置使用
Context
的一个具体子类,则编译器能够解决它,这不会是一个问题


如果您碰巧找到了一种方法,可以在不强制转换或不必插入伪子类的情况下实现这一点,那么请返回报告-但我看不到一种方法,这将与Java泛型可用的语法和语义一起工作。

作为泛型类型,
上下文
不应该在代码中的任何地方显示为未经参数化的。另外
 基本Dispatcher
需要为每个
Dispatcher
[type]参数化和创建,这样它就可以覆盖
进程
(与协变返回类型不同,Java中没有使用逆变参数的自动覆盖)。谢谢,Andrzej!这是一个很好的开始(我确实明白了,sorta)。但是,我发现它并不能完全解决我的问题:当我尝试将“this”传递到dispatch(name,this)时,仍然会遇到类型不匹配的问题“'this'是一个上下文,dispatch需要一个C。我们知道这是一样的,但显然编译器没有。@josh-您是否已将Dispatcher更新为
类Dispatcher
?如果没有,编译器应该(正确地)在那里给您一个原始类型警告,并且在我的头顶上(这台机器上没有JDK)我希望这会将当前不匹配的两个方面统一到
Context
@adrzej-Yup,请参见上面更新的问题--更新Dispatcher-generic并不能解决我的问题。Dispatcher是用正确的类型创建的,但是
进程
方法仍然需要
C
,而Context实例只知道这一点这是一个
上下文
…我现在已经求助于
(C)这个
class Context<C extends Context<C>> {
    private final Dispatcher<C> dispatcher = new Dispatcher<C>();

    public Context() {
        // every context supports the BasicProcessor
        registerProcessor("basic", new BasicProcessor());
    }

    protected void registerProcessor(String name, AbstractProcessor<? super C> processor) {
        dispatcher.registerProcessor(name, processor);
    }

    public void runProcessor(String name) {
        dispatcher.dispatch(name, this); // ERROR: can't cast Context<C> to C
    }
}

// this is totally weird, but it was the only way I could find to provide the
// SpecificContext type to the base class for use in the generic type
class SpecificContext extends Context<SpecificContext> {
    public SpecificContext() {
        // the SpecificContext supports the SpecificProcessor
        registerProcessor("specific", new SpecificProcessor());
    }
}

abstract class AbstractProcessor<C extends Context<C>> {
    public abstract void process(C context);
}

class BasicProcessor extends AbstractProcessor {
    @Override
    public void process(Context context) {
        // ... //
    }
}

class SpecificProcessor extends AbstractProcessor<SpecificContext> {
    @Override
    public void process(SpecificContext context) {
        // ... //
    }
}

class Dispatcher<C extends Context<C>> {
    Map<String, AbstractProcessor<? super C>> processorMap = new HashMap<String, AbstractProcessor<? super C>>();

    public void registerProcessor(String name, AbstractProcessor<? super C> processor) {
        processorMap.put(name, processor);
    }

    public void dispatch(String name, C context) {
        processorMap.get(name).process(context);
    }
}
class Context<C extends Context<C>>
class BasicProcessor extends AbstractProcessor<Context<Context<Context<...
class SpecificContext extends Context<SpecificContext>