- 2011年12月12日 11:42 PM
- Java
まず、Java の配列がタイプセーフではない話。
public class ExampleArray {
public static void main(String[] args) {
String[] strArray = {"test1", "test2"};
Object[] objArray = strArray; // 配列は共変なので代入可能
objArray[0] = new Integer(3); // java.lang.ArrayStoreException
}
}
上記のように、Java の配列は共変という性質を持っているので、Object[] に String[] を代入することができます。つまり、String[] は Object[] のサブクラスである、ということです。
しかし、Generics の場合は、この性質が当てはまりません(Generics は共変ではない)
public class ExampleGenerics {
public static void main(String[] args) {
List<String> strList = new ArrayList<String>();
strList.add("test1");
strList.add("test2");
List<Object> objList = new ArrayList<Object>();
objList = strList; // コンパイルエラー
}
}
なぜ、配列は共変で、Generics は共変ではないのか?(一緒の方が分かりやすいのに)
その理由の前に、
配列の例で見たように、型の混入現象は、強い型付け言語である Java としては避けたい現象です。
配列の場合は、不正な型が混入した場所で例外(java.lang.ArrayStoreException)を投げてくれます。
(これは、結構大事な所で、使用時(get)ではなく、設定時(set)にきちんと例外を投げてくれると、バグの混入場所が特定しやすいです)
なぜこんなことができるかというと、配列は自分が何の型であるかを自身で知っている(バイトコードに型情報が存在する)ので、違う型を入れたときに、自分と違うということが判定できるのです。
一方、Generics の場合はコンパイル時に型消去という操作が行われます。
型消去については、別エントリーでも書いてます(Generics(Java)の型消去について)
Generics のコードは、コンパイル後にはその型情報を一切残していないので、java.lang.ArrayStoreException のような例外を投げることができません。
そのため、共変ではなくして、型の混入を防いでいるのではないかと思います。
Generics で共変っぽいことをしたい場合は、extends とかの境界条件をつければ可能です。
Comments:0
Trackbacks:0
- Trackback URL for this entry
- http://sinsengumi.net/blog/2011/12/%e3%81%aa%e3%81%9c-java-%e3%81%ae%e9%85%8d%e5%88%97%e3%81%af%e5%85%b1%e5%a4%89%e3%81%a7%e3%80%81generics-%e3%81%af%e5%85%b1%e5%a4%89%e3%81%a7%e3%81%af%e3%81%aa%e3%81%84%e3%81%ae%e3%81%8b/trackback/
- Listed below are links to weblogs that reference
- なぜ Java の配列は共変で、Generics は共変ではないのか from sinsengumi血風録