这似乎是一个基本的java问题。
我有一个界面Pipeline
,它有一个方法execute(Stage)
。
然后我创建了一个从Pipeline
扩展的子接口,比如BookPipeline
,我喜欢这个方法execute(BookStage)
。
BookStage
从Stage
延伸。
有关于此的任何建议吗?
答案 0 :(得分:6)
您可能需要考虑使用泛型。
public interface Pipeline<T extends Stage> {
public void execute(T stage);
}
public interface BookPipeline extends Pipeline<BookStage> {
@Override
public void execute(BookStage stage);
}
答案 1 :(得分:4)
除了@Jeffrey作为可能的解决方案所写的内容之外,理解为什么不能这样做也很重要。
假设您的接口Pipeline
包含方法execute(Stage)
,扩展接口BookPipeline
包含execute(BookStage)
。
还假设您有一些实现Conc
的课程BookPipeline
。
考虑以下
Pipeline p = new Conc();
p.execute(new Stage());
会发生什么?这将是不安全的!
Java希望避免它,从而首先防止这种情况发生。
规则是扩展类/接口可以添加行为,但不能减少行为。
答案 2 :(得分:1)
为了详细说明@amit的答案,代码段不安全,因为Conc.execute
方法将BookStage
作为参数,这将尝试挤压Stage
那个地方(当然,并非所有Stage
都是BookStage
s)。
但是,想象一下我们想要采用另一种方式,即将BookePipeline.execute
a super 类型的Stage
设为参数类型,例如{{1 }}
所以只是为了澄清,我们会:
Object
interface Pipeline
{
void execute(Stage s);
}
interface BookPipeline extends Pipeline
{
@Override
void execute(Object s);
}
实施Conc
的地方:
BookPipeline
理论上,这是安全的,因为没有违反Liskov Substitutability - 我们可以安全地将Pipeline p = new Conc();
p.execute(new Stage());
传递给任何带有Stage
参数或更大参数的实现。这被称为逆变。 Java不支持逆变参数类型,但有languages这样做。
您的原始问题涉及协变参数类型,由于指定的原因而不安全(但奇怪的是,一种名为Eiffel的语言允许这样做。)
但是,Java确实支持协变返回类型。想象一下Stage
有一个
Pipeline
Stage getAStage();
覆盖此方法是完全合法的:
BookPipeline
然后想象我们有:
@Override
BookStage getAStage();
假设我们有一些类public void someMethodSomewhere(Pipeline p)
{
Stage s = p.getAStage();
//do some dance on Stage
}
实现了Donc
,并且完全按照Pipeline
中定义的那样覆盖getAStage()
(所以仍然返回Pipeline
)这些电话都可以:
Stage
因为我们总是可以在someMethodSomewhere(new Conc());
someMethodSomewhere(new Donc());
类型的变量中添加Stage
或更少(例如BookStage
)。
因此,为了重新规定与规则重写相关的规则,一个覆盖方法的扩展类/接口,只能使这些方法更接近接受它们并且更多具体返回的内容。(虽然在Java的情况下,只允许更具体的返回类型。)
请记住,PECS - Producer Extends,Consumer Super(Joshua Bloch,Effective Java)