これは基本的なJavaの質問のようです。
Pipeline
メソッドを持つインターフェースが1つありますexecute(Stage)
。
次に、から拡張するサブインターフェイスを作成します。Pipeline
たとえばBookPipeline
、メソッドが好きexecute(BookStage)
です。
BookStage
から拡張しStage
ます。
この種の定義はjavaコンパイルを渡すことができなかったようです。
それについて何か提案はありますか?
ジェネリックの使用を検討することをお勧めします。
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
をパラメーターとして受け取り、その代わりに a をスクイーズしようとするため、コード スニペットは安全Stage
ではありません (もちろん、すべてStage
の s がBookStage
s であるとは限りません)。
ただし、別の方法、つまり のパラメータ型を のような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 Substitutability に違反していないため、これは理論的には安全です。パラメータ以上を取るStage
実装には a を安全に渡すことができます。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()
Pipeline
Stage
someMethodSomewhere(new Conc());
someMethodSomewhere(new Donc());
type の変数にはいつStage
でも a 以下 (例: ) を入れることができるからです。BookStage
Stage
したがって、ルールをメソッドのオーバーライドに特に関連するように言い換えると、メソッドをオーバーライドする拡張クラス/インターフェースは、それらのメソッドが受け入れるものをより一般化し、それらが返すものをより具体的にするだけです。(ただし、Java の場合は、より具体的な戻り値の型のみが許可されます。)
覚えておいてください、PECS - Producer Extends、Consumer Super (Joshua Bloch、Effective Java)