2016-07-19 3 views
11

ジェネリックとキャスティングは理解していますが、ジェネリックキャスティングは理解できません。私は、特定のタイプのアップまたはダウン継承ツリーをキャストすることができます思ったが、これは私が間違って証明した:これは最良の例ではないかもしれませんが、うまくいけば、あなたが私のポイントを取得しますジェネリック変数へのキャスト

ArrayList<?> cislo = (ArrayList<? extends Number>) new ArrayList<Integer>(); 

。これはどのように作動しますか?どのような型にそのキャストを取得するには?

+1

汎用情報が失われる(型消去)ので、実行時にキャストはまったくありません。コンパイル時に、 'ArrayList 'を 'ArrayList <? 'として扱うようにコンパイラに指示します。 'Number'変数を' Integer'にキャストした場合と同じです。コンパイラには何をしているのかを伝えます。 'ArrayList 'への代入はどんな場合でも動作します。 – Thomas

+0

ジェネリックスでは、キャスティングは必要ありません。ジェネリックタイプをキャスティングしたいと思えば、ジェネリックの巨大な柔軟性を使用するだけで、キャストなしで「クリーン」なソリューションがないかどうかを確認する必要があります。具体的な事例があれば、多くの人が助けてくれると確信しています。 – martinhh

+0

具体的な例があります。私は、@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(); }} ' –

答えて

4

キャストは不要です。

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によって示されるタイプのセットのサブセットである。

  • ?拡張T < =? Sを延長する場合:S

  • ?拡張T < =?この定義ArrayList<? extends Number>によって

[...]だから、

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

+0

"キャストは不要です。"私が言ったように、最良の例にはならない。私は本当に読みにくいですが、あなたの説明は本当に助けになりました。追加情報はこちらhttp://stackoverflow.com/questions/2776975/how-can-i-add-to-list-extends-number-data-structures –

関連する問題