SetとSetの違いまとめ
どうやら「Set
要素の追加
「set.add(object);」で縦軸の型のオブジェクトを追加可能かどうか。
Set<Object> | Set<String> | Set<?> | Set | ||||||
---|---|---|---|---|---|---|---|---|---|
Object | ○ | × | × | ○ | |||||
String | ○ | ○ | × | ○ |
- 「Set
」,「Set」は任意のオブジェクトを受け付けるのでString,Object共にOK - 「Set
」はStringのみ受け付けるので、StringだけOK - 「Set<?>」は何も追加できない。(何を受け付けるか不明であるため?)
要素の取得
「set.iterator().next();」で取得できる要素が縦軸の型の変数にキャストなしで代入可能かどうか。
Set<Object> | Set<String> | Set<?> | Set | ||||||
---|---|---|---|---|---|---|---|---|---|
Object | ○ | ○ | ○ | ○ | |||||
String | × | ○ | × | × |
- 「Set
」,「Set」,「Set<?>」の中身は不明またはObjectなのでObjectにしか代入できない。 - 「Set
」の要素はStringなので、ObjectまたはStringに代入できる。
代入
「setA = setB;」のように、を横軸の型のSetBを縦軸の型のSetAに代入できるか。
A↓B→ | Set<Object> | Set<String> | Set<?> | Set | |||||
---|---|---|---|---|---|---|---|---|---|
Set<Object> | - | × | × | ○ | |||||
Set<String> | × | - | × | ○ | |||||
Set<?> | ○ | ○ | - | ○ | |||||
Set | × | × | ○ | - |
- 「Set
」に「Set 逆もしかり。」は代入できない。 - これは以下のようなパターンがあり得るかららしい(→「Generics in the Java Programming Language ※注:pdfファイル」の「3 Generics and Subtyping」より)
Set<String> setS = null; Set<Object> setO = setS; // Set<Object>にSet<String>を代入 setO.add( new Object() ); // Set<String>にObjectが追加されてしまう!!
- 「Set
」、「Set 」は「Set」にも代入できない。縮小変換になるため。 - Set<?>にはすべてのSetが代入できる。
Setごと追加
「setA.addAll(setB);」のように、横軸の型のSetBを縦軸の型のSetAにまとめて追加できるか。
A↓B→ | Set<Object> | Set<String> | Set<?> | Set | |||||
---|---|---|---|---|---|---|---|---|---|
Set<Object> | - | ○ | ○ | ○ | |||||
Set<String> | × | - | × | ○ | |||||
Set<?> | × | × | - | ○ | |||||
Set | ○ | ○ | ○ | - |
- 「Set」は、すべてのSetのaddAll()に指定できるが安全ではない。
- SetはObject等任意の値が入るため。
- 例えば、「Set
#addAll()」の引数に、Integerを含むSetを指定した場合「Set 」にInteger型の要素が追加されます。追加時にはエラーになりませんが、要素取得時にjava.lang.ClassCastExceptionになります。
Set set = new HashSet(); set.add( "String" ); set.add(1); Set<String> setS = new HashSet<String>(); setS.addAll( set ); // コンパイルエラーにならない。また、実行時エラーにもならない。 for ( String str : setS ) {} // 実行時にここでjava.lang.ClassCastExceptionが発生。
- 「Set
」は、すべてのSetのaddAll()に指定できる。
まとめ
- 「Set
」 - Objectとその派生クラスを持つSet。
- 「Set
」は「Set 」型の変数に代入できないので注意。
- 「Set
」 - Stringとその派生クラスを持つSet。
- 「Set<?>」
- こいつが問題。なにを持つか不明なSet、という理解でいいのかな?
- なにを持つか不明なので、何も追加できない && 値はObjectとしてしか取り出せない。
- 「Set
」や「Set 」を抽象化して透過的に扱いたい時に使う?
- 「Set」
- 任意の要素を持ち得る旧世代のSet。使用禁止。
以上。...「Set」=「Set
補足:検証で使用したコード
検証で使用したコードは以下。コメントアウトされているところはコンパイルエラーになります。
Set set1 = new HashSet(); // Setは任意の要素を受け付ける Set<Object> set2 = new HashSet<Object>(); // SetはObjectを受け付ける(派生クラスもOK) Set<String> set3 = new HashSet<String>(); // SetはStringを受け付ける(派生クラスもOK)。 Set<?> set4 = new HashSet<Object>(); // Setは任意の要素を持つ。実際に何を保持しているかは不明であるため、データの追加は行えない。 // 要素の追加 set1.add( "" ); set1.add( new Object() ); set2.add( "" ); set2.add( new Object() ); set3.add( "" ); //set3.add( new Object() ); //set4.add( "" ); //set4.add( new Object() ); // 取得 String s; Object o; o = set1.iterator().next(); //s = set1.iterator().next(); o = set2.iterator().next(); //s = set2.iterator().next(); o = set3.iterator().next(); s = set3.iterator().next(); o = set4.iterator().next(); //s = set4.iterator().next(); // 代入。 //set1 = set2 //set1 = set3 set1 = set4; set2 = set1; //set2 = set3; //set2 = set4; set3 = set1; //set3 = set2; //set3 = set4; set4 = set1; set4 = set2; set4 = set3; // Setごと追加 set1.addAll( set2 ); set1.addAll( set3 ); set1.addAll( set4 ); set2.addAll( set1 ); set2.addAll( set3 ); set2.addAll( set4 ); set3.addAll( set1 ); // コンパイルエラーにはならないが安全ではない! SetにはObjectなど任意の要素が含まれる可能性があるため。 //set3.addAll( set2 ); //set3.addAll( set4 ); set4.addAll( set1 ); //set4.addAll( set2 ); //set4.addAll( set3 );