0

次の構文が正しくないことはわかっています。

void dolist2(List<? extends Number> list) {
    list.add(new Integer(3));
}

しかし、コンパイラがそれが合法ではないことをどのように認識しているかはわかりません。List.java のソース コードを見ると、次のように表示されます。

boolean add(E e);

@IllegalWhenInvokedOnUpperBoundReference のような注釈でさえ、この宣言について特別なことは何も見当たりませんコンパイラは、この制限を強制することをどのように認識していますか? 自分のクラスに同様の制限を設定するにはどうすればよいですか?

4

4 に答える 4

3

Integerは のインスタンスではないためです? extends Number? extends Number意味: Number である、または Number を拡張する未知の型。型が不明であるため、コンパイラは Integer が有効な型であると判断できず、コンパイルを拒否します。

List<Integer>コンパイラは String が Integer を拡張しないことを認識しているため、どちらにもString を追加することはできません。型チェックは、コンパイラの役割の 1 つです。

これは List が持つ特別なものであり、コードにはないものだと考えているようです。そうではありません。これは、ジェネリック型のルールにすぎません。

public class Whatever<T> {
    public void foo(T e) {
    }

    public static void main(String[] args) {
        Whatever<? extends Number> w = new Whatever<Integer>();
        w.foo(new Integer(4)); // won't compile
    }
}
于 2013-08-22T06:59:27.773 に答える
2

Java ジェネリックでは、ワイルドカードの境界には次の 2 種類があります。

  • ? extends Y

  • ? super Y

最初の形式 ,は、あなたが持っているものは のサブクラスであることが保証されているが、どのサブクラスであるかは保証されていないことあなたとextendsコンパイラに伝えます. タイプが渡すタイプと互換性があるという保証がないため、そのようなワイルドカードに書き込むことはできません。YextendsY

2 番目の形式 はsuper、ユーザーとコンパイラに、クラスが最大でも a を取ることが保証されていることを伝えますY。値は、それ自体またはのスーパークラスのYいずれかを期待しているため、型のインスタンスを喜んで取得します...したがって、いつでも値をワイルドカードにすることができます。YYwritesuper

2 種類のワイルドカードを使用したコード例を次に示します。

public static <T> void copy(List<? super T> dest, List<? extends T> src) {
  for (T t: src) dest.add(t);
}
于 2013-08-22T07:29:10.343 に答える
2

Numberコンパイラは、 inの任意のサブタイプの List を渡すことができることを認識していますList<? extends Number>。したがって、任意のものを渡すことができList<Double>ますList<Float>

現在、メソッドが取得する型を確実に確認できないため、リストに何かを追加すると、型安全ではなく、ヒープ汚染が発生します。したがって、以下のステートメント:

list.add(new Integer(3));

安全ではありません。に追加Integerしている可能性がありますList<Double>。これらの型には互換性がないため、実行時に失敗します。したがって、コンパイラはエラーを出します。この概念はPECS (Producer Extends Consumer Super)としてよく知られています。


おすすめの読み方:

于 2013-08-22T06:58:19.847 に答える