私は次のようなものを持っています:
List<? extends BaseClass> a = getMyList();
次の 2 つの命令はいずれも無効であり、コンパイラは引数として "? extends BaseClass" が必要であると言います。
a.add(new BaseClass());
a.add(new SubClass());
問題はそれだと思います
これはどのように解決できますか?
List<? super BaseClass> a
それに何かを追加する必要があります。あなたはからのものだけを得ることができますList<? extends BaseClass> a
。
これを見てくださいPECS(プロデューサーはコンシューマースーパーを拡張します)とは何ですか?。
問題は、コンパイラがリストの実際の型を判断する方法がないことです。
タイプが である可能性がありますSubClass
。その場合、 を追加することはできませんBaseClass
。またはを追加できないことを意味し
ます。SubSubClass
BaseClass
SubClass
ただし、これはコンパイルされます:
List<BaseClass> a = getMyList();
a.add(new BaseClass());
a.add(new SubClass());
List<? extends Something>
通常、Javaチュートリアルでは、コンパイラがリスト内の有効なタイプを認識できないため、に何も追加できないと述べています。
この説明は直感的ではなく、厳密には真実ではありません。コンパイラが賢い存在であると偽っており、aList
が要素の順序付けられたコンテナであることを理解し、潜在的に危険なことを行うのを防ぎます。実際には、コンパイラは単なるプログラムであり、いくつかの規則に従うだけです。
したがって、ロールプレイングを行い、コンパイラのように考えるのが最善です。あなたが持っている
interface List<E> {
void add(E element);
}
コンテナタイプ<E>
を定義していることを認識していないという意味で、コンパイラに追加のセマンティクスを提供しないことに注意してください。を定義することもできますが、コンパイラーの場合は問題ではありません。または、同じルールが適用されます(明らかに、コンテナータイプではありません。つまり、象には何も追加しません。願っています...)Asdf<Q>
Elephant<W>
Elephant
したがって、タイプの参照を宣言しますList<? extends Shape>
。コンパイラは同様のことを理解します
abstract class Unknown extends Shape {}
class ListOfUnknown {
void add(Unknown element) {}
Unknown get(int index) {}
}
Rectangle
そのようなリストにを追加できない理由がわかりますか?通常のJava規則に従って、サブタイピング関係によってインターフェースの互換性が保証されているRectangle
などの理由で、メソッドにを指定できます。add(Shape)
型のadd(Unknown)
引数で呼び出すことができるようにするには、の子である必要がありますが、拡張するだけなので、ここではジェネリックに特別なことは何もありません。これは、型の互換性に関する通常のJavaルールです。呼び出すことができるようにするには、型または同等のオブジェクト(拡張するクラス)への参照が必要ですが、ご覧のとおり、そのような型はどこにも定義されていないため、最終的にはこのリストへのアクセスが禁止されます。Rectangle
Rectangle
Unknown
Rectangle
Shape
add(Unknown)
Unknown
Unknown
add()
ジェネリック医薬品を勉強するときは、常に「なぜ」と自問してください。List
ジェネリックがコレクションに主に追加されたとしても、それらは言語機能であるため、例にとどまることはありません。したがって、コンテナータイプの特定の実装に集中するのではなく、ジェネリックが実行するセマンティクスを理解する必要があります。