Javaの場合:
Cage<? extends Animal> animals = null;
これは檻ですが、どんな動物を受け入れるのかわかりません。
animals = lions; // Works!
さて、あなたはケージ動物の種類について意見を追加しないので、ライオンは予想に違反しません。
animals.add(new Lion()); // Error!
あなたはケージの動物の種類がわからない。この特定のケースでは、ライオンを入れるライオンのケージになりますが、それを許可するルールでは、あらゆる種類の動物を任意のケージに入れることができます。適切に禁止されています。
Scalaでは::
extendsのCage[+T]場合、aは。と見なされます。BACage[B]Cage[A]
それを考えると、animals = lions許可されます。
ただし、これはjavaとは異なり、typeパラメーターは間違いなくAnimalワイルドカードではありません? extends Animal。に動物を入れることができCage[Animal]ます。ライオンは動物なので、ケージ[鳥]である可能性のあるケージ[動物]にライオンを入れることができます。これはかなり悪いです。
それが実際に許可されていないことを除いて(幸いなことに)。あなたのコードはコンパイルされるべきではありません(あなたのためにコンパイルされた場合、あなたはコンパイラのバグを観察しました)。共変ジェネリックパラメーターをメソッドの引数として表示することはできません。その理由は、それを許可するとライオンを鳥かごに入れることができるからです。T+Tはの定義のように表示さCageれますが、メソッドの引数として表示することはできませんadd。
したがって、どちらの言語でも、ライオンを鳥かごに入れることは許可されていません。
更新された質問について。
そうでなければトラが追加される可能性があるため、それは行われますか?
はい、もちろんこれが理由です。型システムのポイントはそれを不可能にすることです。それは実行時エラーを引き起こしますか?おそらく、ある時点ではそうなりますが、実際のジェネリック型は実行時にチェックされないため(型消去)、addを呼び出した時点ではそうではありません。しかし、型システムは通常、エラーが発生したことを証明できるプログラムだけでなく、(ある種の)エラーが発生しないことを証明できないすべてのプログラムを拒否します。
動物のサブタイプが1つしかない場合に、それを拒否しない特別な(仮想の)ルールを作成できますか?
多分。あなたはまだ2種類の動物、すなわちAnimalとを持っていることに注意してくださいLion。したがって、重要な事実は、Lionインスタンスが両方のタイプに属しているということです。一方、Animalインスタンスはタイプに属していませんLion。animals.add(new Lion())許可される可能性があります(ケージは任意の動物用のケージ、またはライオン専用のケージのいずれかであり、どちらも問題ありません)が、許可されるanimals.add(new Animal())べきではありません(動物はライオン専用のケージである可能性があるため)。
しかしとにかく、それは非常に悪い考えのように聞こえます。オブジェクト指向システムの継承のポイントは、後で、他の場所で作業している他の誰かがサブタイプを追加できることです。これにより、正しいシステムが正しくなくなることはありません。実際、古いコードを再コンパイルする必要すらありません(おそらくソースがありません)。そのようなルールでは、それはもはや真実ではないでしょう