質問で最初に参照する概念は、共変戻り型と呼ばれます。
メソッドが特定の型のオブジェクトを返すことになっているため、共変の戻り型が機能し、オーバーライドするメソッドは実際にそのサブクラスを返す場合があります。Javaのような言語のサブタイピングルールに基づいて、S
がのサブタイプであるT
場合、T
表示される場所はどこでもを渡すことができS
ます。
そのためS
、を予期したメソッドをオーバーライドするときにを返すのは安全T
です。
メソッドのオーバーライドが、オーバーライドされたメソッドによって要求されたもののサブタイプである引数を使用することを受け入れるというあなたの提案は、型システムに不健全さをもたらすため、はるかに複雑です。
一方では、上記と同じサブタイピング規則により、おそらくあなたがしたいことに対してすでに機能しているでしょう。例えば
interface Hunter {
public void hunt(Animal animal);
}
このクラスの実装は、あなたの質問の基準をすでに満たしているため、いかなる種類の動物も受け取れません。
しかし、あなたが提案したようにこのメソッドをオーバーライドできるとしましょう:
class MammutHunter implements Hunter {
@Override
public void hunt(Mammut animal) {
}
}
ここに面白い部分があります、今、あなたはこれをすることができます:
AnimalHunter hunter = new MammutHunter();
hunter.hunt(new Bear()); //Uh oh
AnimalHunter
あなたの公開インターフェースによると、どんな動物も狩ることができるはずですが、あなたの実装によるMammutHunter
と、Mammut
オブジェクトのみを受け入れます。したがって、オーバーライドされたメソッドは、パブリックインターフェイスを満たしていません。ここで型システムの健全性を壊しました。
ジェネリックを使用して、必要なものを実装できます。
interface AnimalHunter<T extends Animal> {
void hunt(T animal);
}
次に、MammutHunterを定義できます
class MammutHunter implements AnimalHunter<Mammut> {
void hunt(Mammut m){
}
}
また、一般的な共分散と反分散を使用すると、必要に応じてルールを緩和できます。たとえば、哺乳動物ハンターは特定のコンテキストでのみネコ科の動物を狩ることができます。
AnimalHunter<? super Feline> hunter = new MammalHunter();
hunter.hunt(new Lion());
hunter.hunt(new Puma());
MammalHunter
implementsを想定していますAnimalHunter<Mammal>
。
その場合、これは受け入れられません。
hunter.hunt(new Mammut()):
マンマットが哺乳類の場合でも、ここで使用している反変種の制限により受け入れられません。したがって、あなたが言及したようなことをするために、型をある程度制御することができます。