这似乎是一个基本的java问题。
我有一个接口,Pipeline它有一个方法execute(Stage)。
然后我创建一个子接口来扩展Pipeline,比如说BookPipeline,我喜欢这个方法execute(BookStage)。
BookStage从 延伸Stage。
似乎这种定义无法通过 java compile。
对此有什么建议吗?
您可能需要考虑使用泛型。
public interface Pipeline<T extends Stage> {
public void execute(T stage);
}
public interface BookPipeline extends Pipeline<BookStage> {
@Override
public void execute(BookStage stage);
}
除了@Jeffrey 写的可能的解决方案之外,了解您为什么不能这样做也很重要。
假设您有一个Pipeline带有方法的接口execute(Stage),以及一个BookPipeline带有execute(BookStage).
还假设您有一些Conc实现BookPipeline.
考虑以下
Pipeline p = new Conc();
p.execute(new Stage());
会发生什么?会很不安全!
Java 想要避免它,从而从一开始就防止这种情况。
规则是扩展类/接口可以添加行为,但不能减少行为。
只是为了详细说明@amit 的答案,代码片段是不安全的,因为该Conc.execute方法将 aBookStage作为参数,这将试图挤压 aStage来代替它(当然,并非所有Stages 都是BookStages)。
但是,想象一下我们想走另一条路,即将参数类型设为BookePipeline.execute的超类型Stage,例如Object.
因此,为了澄清,我们将:
interface Pipeline
{
void execute(Stage s);
}
interface BookPipeline extends Pipeline
{
@Override
void execute(Object s);
}
在哪里Conc实现BookPipeline:
Pipeline p = new Conc();
p.execute(new Stage());
从理论上讲,这将是安全的,因为没有违反 Liskov 可替换性 - 我们可以安全地将 a 传递给Stage任何采用Stage参数或更大参数的实现。这称为逆变。Java 不支持逆变参数类型,但是有些语言支持。
您最初的问题与协变参数类型有关,由于指定的原因,这是不安全的(但奇怪的是,一种名为Eiffel的语言允许这样做)。
然而,Java 确实支持协变返回类型。想象Pipeline有一个
Stage getAStage();
BookPipeline像这样覆盖这个方法是完全合法的 :
@Override
BookStage getAStage();
然后想象我们有:
public void someMethodSomewhere(Pipeline p)
{
Stage s = p.getAStage();
//do some dance on Stage
}
假设我们有一些完全按照定义的类Donc实现Pipeline和覆盖(所以仍然返回),这两个调用都可以:getAStage()PipelineStage
someMethodSomewhere(new Conc());
someMethodSomewhere(new Donc());
因为我们总是可以将 aStage或任何更少(例如BookStage)放入类型为 的变量中Stage。
因此,将规则改写为专门与方法覆盖相关,覆盖方法的扩展类/接口只能使这些方法在它们接受的内容上更通用,在返回的内容上更具体。(尽管在 Java 的情况下,只允许更具体的返回类型。)
请记住,PECS - Producer Extends,Consumer Super(Joshua Bloch,Effective Java)