キャストは不要です。
ArrayList<?> list = new ArrayList<Integer>();
ArrayList<? extends Number> list2 = new ArrayList<Integer>();
割り当ては明示的なキャストを必要としません。
ワイルドカードの種類がコンクリートのタイプよりも「より一般的な」/「以下特異的」タイプであり、upper bounded wildcard types(等? extends Number
)は(?
)unbounded onesより特異的です。
ワイルドカードの種類の詳細については、Oracle Tutorial on Wildcards and Subtypingを参照してください。
この4.10.2. Subtyping among Class and Interface Types
ジェネリック型宣言C(N> 0)が与えられ、パラメータ化された型のTi(1≤iがN以下)Cの直接のスーパータイプである特定JLSの要部
- Dここで、Dは汎用タイプCの直接スーパータイプであり、θは置換[F1:= T1、...、Fnです。 = = Tn]となる。
- Cここで、SiはTi(1≦i≦n)を含む(§4.5.1)。
[...]設定されている場合、型引数T1が別の型引数T2を含むと言われ 4.5.1. Type Arguments of Parameterized Types
、書き込まT2 < = T1を指す
T2によって示されるタイプのタイプは、おそらく、以下のルール(<:はサブタイプ(§4.10)を示す)の再帰的および推移的閉包の下でT1によって示されるタイプのセットのサブセットである。
[...]だから、
はArrayList<Integer>
とArrayList<?>
のスーパーで生タイプ以外のすべてのArrayList<>
のスーパータイプです。
スーパータイプであるタイプの変数への代入は、キャストする必要はありません。そのキャスト後
Object list = new ArrayList<Integer>();
//...somewhere else - the compiler does not know that list is always an ArrayList, but we tell it that we know what we are doing
List<? extends Number> numbers = (List<? extends Number>) list; //unchecked cast warning, but works
、あなたが例えばすることができます
キャストを使用すると、さまざまなタイプのものを代入したい場合に必要ですリストから要素を取得し、Number
として扱います。あなたは
は、問題が発生し始め
java.lang.ClassCastException: java.util.HashSet cannot be cast to java.util.List
を投げて、実行時に失敗したList<? extends Number>
Object list = new HashSet<Integer>();
List<? extends Number> numbers = (List<? extends Number>) list; //unchecked cast warning
のサブタイプではありません
list
参照に何かを割り当てた場合、キャストは実行時に失敗しますジェネリックタイプが一致しない場合:
List<String> stringList = new ArrayList<String>();
stringList.add("hi");
Object list = stringList;
List<? extends Number> numbers = (List<? extends Number>) list; //unchecked cast warning, but (sadly) works
Number n = numbers.get(0); //fails: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number
これは、実行時にリストタイプの消去が一致するために発生します。参照the tutorial on erasure
汎用情報が失われる(型消去)ので、実行時にキャストはまったくありません。コンパイル時に、 'ArrayList'を 'ArrayList <? 'として扱うようにコンパイラに指示します。 'Number'変数を' Integer'にキャストした場合と同じです。コンパイラには何をしているのかを伝えます。 'ArrayList >'への代入はどんな場合でも動作します。 –
Thomas
ジェネリックスでは、キャスティングは必要ありません。ジェネリックタイプをキャスティングしたいと思えば、ジェネリックの巨大な柔軟性を使用するだけで、キャストなしで「クリーン」なソリューションがないかどうかを確認する必要があります。具体的な事例があれば、多くの人が助けてくれると確信しています。 – martinhh
具体的な例があります。私は、@ReesmoConfiguration(storage = RestApiStorage.class)と抽象スーパークラスのストレージに、私はファクトリメソッドを見つけました。結果を送付したいストレージを選択するためにJUnitテストに注釈を付けることができるフレームワークを使って作業します。 newInstance(Object configuration){ クラス<?ストレージ> clazz = nullを拡張します。 if(Bool.FALSE.equals(Property.ENABLED.get(configuration))){ clazz = DummyStorage.class; } else { clazz =(Class <?extends Storage>)Property.STORAGE.get(構成); } if(clazz.isAssignableFrom(DummyStorage.class)){ return新しいDummyStorage(); }} ' –