关于Java子接口子类型

关于Java子接口子类型,java,interface,Java,Interface,这似乎是一个基本的java问题 我有一个接口,Pipeline,它有一个方法execute(Stage) 然后我创建一个子接口来扩展管道,比如说BookPipeline,我喜欢方法是execute(BookStage) BookStage扩展自Stage 这种定义似乎无法通过java编译 有什么建议吗? < P>你可能想考虑使用泛型。 public interface Pipeline<T extends Stage> { public void execute(T sta

这似乎是一个基本的java问题

我有一个接口,
Pipeline
,它有一个方法
execute(Stage)

然后我创建一个子接口来扩展
管道
,比如说
BookPipeline
,我喜欢方法是
execute(BookStage)

BookStage
扩展自
Stage

这种定义似乎无法通过java编译


有什么建议吗?

< P>你可能想考虑使用泛型。

public interface Pipeline<T extends Stage> {
     public void execute(T stage);
}

public interface BookPipeline extends Pipeline<BookStage> {
     @Override
     public void execute(BookStage stage);
}
公共接口管道{
公开无效执行(T阶段);
}
公共接口管道扩展了管道{
@凌驾
公开作废执行(BookStage阶段);
}

除了@Jeffrey所写的可能的解决方案之外,理解您为什么不能这样做也很重要

假设您有一个带有方法
execute(Stage)
的接口
Pipeline
,以及一个带有
execute(BookStage)
的扩展接口
BookPipeline

还假设您有一个类
Conc
,它实现了
BookPipeline

考虑以下几点

Pipeline p = new Conc();
p.execute(new Stage());
会发生什么?这是不安全的!
Java希望避免这种情况,因此从一开始就避免了这种情况


规则是,扩展类/接口可以添加行为,但不能减少它

仅就@amit的答案进行详细说明,代码片段是不安全的,因为
Conc.execute
方法将
BookStage
作为参数,这将试图压缩一个
阶段
(当然,并非所有的
Stage
s都是
BookStage
s)

但是,假设我们想走另一条路,也就是说,将
BookEpiLine.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可替换性没有被违反-我们可以安全地将
阶段
传递到任何采用
阶段
参数或更大参数的实现中。这称为逆变。Java不支持逆变参数类型,但也有支持逆变参数类型的

您最初的问题与协变参数类型有关,由于指定的原因,协变参数类型是不安全的(不管多么奇怪,一种称为的语言允许这样做)

但是Java支持协变返回类型

Stage getAStage();
BookPipeline
这样覆盖此方法是完全合法的:

@Override
BookStage getAStage();
然后想象我们有:

public void someMethodSomewhere(Pipeline p)
{
  Stage s = p.getAStage();
  //do some dance on Stage
}
假设我们有一个类
Donc
,它实现了
Pipeline
,并完全按照
Pipeline
中的定义重写了
getAStage()
(因此仍然返回
Stage
),这两个调用都可以:

someMethodSomewhere(new Conc());
someMethodSomewhere(new Donc());
因为我们总是可以在类型为
Stage
的变量中放置
Stage
或任何更小的内容(例如
BookStage

因此,为了将规则改写为专门与方法重写相关,重写方法的扩展类/接口只能使这些方法在接受的内容上更加通用,在返回的内容上更加具体。(尽管在Java中,只允许使用更具体的返回类型。)


请记住,PECS-Producer Extends,Consumer Super(约书亚·布洛赫,高效Java)

编译器错误消息是什么?你的代码是什么?执行的声明不是在
BookPipline
redudant中吗?@KirkWoll是的,它是为了示例而存在的,我不需要重写它。非常感谢!