2

私はこのシナリオを持っていますが、なぜJavaはクラス階層を尊重していないのですか?

import ...

public class GenericsTest {

    public static void main(String[] args) {
        List<Integer> myList = new ArrayList<Integer>();
        myList.add(1);
        myList.add(new Integer(2));
        new GenericsTest().doInsert(myList);
    }

    private void doInsert(List<? extends Number> myList) { // Number <- Integer
        myList.add(new Integer(1)); // This don't compiles
    }
}

誰かがこれを説明できますか?ありがとう!!!

4

4 に答える 4

2

ジェネリックのワイルドカードは、「何でも」という意味ではなく、「わからない」という意味です。「数値List<? extends Number>を拡張するものなら何でも保持できるリスト」ではありません。「数を拡張するもののリストですが、それらが何であるかはわかりません」です。したがって、整数を追加することは違法です。整数が、これがリストである数値を拡張するものであるかどうかがわからないためです。Number を拡張するもののリストはただList<Number>.

于 2013-02-27T20:06:20.657 に答える
1

あなたが提供したコードが合法である場合、次のコードで何が起こるか想像してみてください:

List<Double> listDouble = new ArrayList<Double>();
doInsert(listDouble);

Double d = listDouble.get(0); //ClassCastException!

コンパイラは、最後の行に暗黙のキャストを追加します。このキャストは実行時に失敗し、ジェネリックの型の安全性の保証が破られます。これは、コンパイラがリストの内容とデータ型の仮定を台無しにすることを防げなかったためです。Double 値のみを保持するはずでしたが、内部に整数が見つかりました。

オプション:

doInsert(List<? extends Number> myList)

数値の反復は許可しますが、コレクションへの追加は許可しません。Number の任意のサブタイプで定義されたリストを受け入れます。

doInsert(List<Number> myList)

繰り返しと変更を許可しますが、List<Number> として正確に定義されたリストのみを受け入れます。

doInsert(List<? super Number> myList)

項目を (オブジェクトとして) 反復処理できるようにし、任意の種類の数値を追加できるようにします。その祖先の数のリストのみを受け入れます (この場合、実質的に役に立たない理由)。

于 2013-02-27T20:09:03.197 に答える
0

許容できると仮定して、次の反例を考えてみましょう。

public class GenericsTest {
  public static void main(String[] args) {
    List<Integer> myList = new ArrayList<Integer>();
    myList.add(1);
    myList.add(new Integer(2));

    List<Integer> myDoubleList = new ArrayList<Double>();
    myList.add(1.0);
    myList.add(new Double(2));
    new GenericsTest().doInsert(myList); // Here you're trying to add an Integer into a List<Double>
  }

  private void doInsert(List<? extends Number> myList) { // Number <- Integer
    myList.add(new Integer(1)); // This don't compiles
  }

}
于 2013-02-27T20:15:45.157 に答える
0

これが機能しない理由は、参照される List の型が整数である必要がないためです。ただし、以下はコンパイルされます。

private void doInsert(List<Number> myList) { 
    myList.add(new Integer(1));
}

一緒に:

private void doInsert(List<? extends Number> myList) { 
    ((List<Number>)myList).add(new Integer(1));
}  

@Eyal Schneider からのコメントに基づいてこの回答を追加し、正しく設定した場合にリストされている 2 番目の方法が機能することを示しました。それはおそらく良いことではありませんが。

public class Test{  
    public void doInsert(List<? extends Number> myList) { 
        ((List<Number>)myList).add(new Integer(1));
        ((List<Number>)myList).add(new Short("2"));
        ((List<Number>)myList).add(new BigDecimal("3"));
        ...
    }  

    public static void main(String[] args){
        Test t=new Test();
        List<Number> list=new ArrayList<Number>();
        t.doInsert(list);
            for(Number number:list)
                System.out.println(number);
    }
}
于 2013-02-27T20:10:38.023 に答える