2

私は次のようなものを持っています:

List<? extends BaseClass> a = getMyList();

次の 2 つの命令はいずれも無効であり、コンパイラは引数として "? extends BaseClass" が必要であると言います。

a.add(new BaseClass());
a.add(new SubClass());

問題はそれだと思います

これはどのように解決できますか?

4

3 に答える 3

3

List<? super BaseClass> aそれに何かを追加する必要があります。あなたはからのものだけを得ることができますList<? extends BaseClass> a

これを見てくださいPECS(プロデューサーはコンシューマースーパーを拡張します)とは何ですか?

于 2012-09-21T19:17:03.677 に答える
2

問題は、コンパイラがリストの実際の型を判断する方法がないことです。

タイプが である可能性がありますSubClass。その場合、 を追加することはできませんBaseClass。またはを追加できないことを意味し
ます。SubSubClassBaseClassSubClass

ただし、これはコンパイルされます:

List<BaseClass> a = getMyList();
a.add(new BaseClass());
a.add(new SubClass());
于 2012-09-21T19:17:37.160 に答える
1

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ルールです。呼び出すことができるようにするには、型または同等のオブジェクト(拡張するクラス)への参照が必要ですが、ご覧のとおり、そのような型はどこにも定義されていないため、最終的にはこのリストへのアクセスが禁止されます。RectangleRectangleUnknownRectangleShapeadd(Unknown)UnknownUnknownadd()

ジェネリック医薬品を勉強するときは、常に「なぜ」と自問してください。Listジェネリックがコレクションに主に追加されたとしても、それらは言語機能であるため、例にとどまることはありません。したがって、コンテナータイプの特定の実装に集中するのではなく、ジェネリックが実行するセマンティクスを理解する必要があります。

于 2012-09-22T13:45:36.833 に答える