Kōhei Yamamoto

Effective Java 第 2 版:第 5 章 項目 24, 25

項目 24: 無検査警告を取り除く

型パラメータを書いていないなどの理由で、コンパイル時に無検査警告が出ることがある。 無検査警告は全て取り除くべきである。 なぜなら、全ての警告を取り除けば、そのコードは型安全であると保証できるからである。

もし、警告を取り除くことができなくても、そのコードが型安全であると確かに示せるならば、

@SuppressWarnings("unchecked")

というアノテーションにより、警告を抑制することができる。 このアノテーションは、できるだけ小さいスコープに対して用いるべきである(一つの変数宣言など)。 また、警告を抑制するときは、他者が理解しやすいように、コメントに理由を書くべきである。

項目 25: 配列よりリストを選ぶ

ジェネリックな配列は作れないという話。 まずイレイジャについて説明したあと、なぜジェネリックな配列が作れないか説明する。

イレイジャ

イレイジャはジェネリックスを実現するための機構である。 型パラメータを持つ宣言は、コンパイル時にイレイジャによって型パラメータの情報が消される。 例えば、以下のコードを考える。

List<Integer> list= new ArrayList<Integer>();

このコードは、実行時は以下のコードと見なされる。

List list = new ArrayList();

イレイジャで実行時は型情報を破棄することで、ジェネリックスを使っていない過去のコードと相互運用できるようにしてある。

なぜジェネリックな配列は作れないか

以下のコードの 1 行目にあるような、ジェネリックな配列は作れない。

List<String>[] stringListss = new List<String>[1];    // ここでコンパイルエラー
List<Integer> intList = Arrays.asList(42);
Object[] objects = stringLists;
objects[0] = intList;
String s = stringLists[0].get(0);

このコードがコンパイルできるとする。 このとき、実行時のコードは以下の通りとなる。

List[] stringListss = new List[1];
List intList = Arrays.asList(42);
Object[] objects = stringLists;
objects[0] = intList;
String s = stringLists[0].get(0);

1, 2 行目では、イレイジャによって、型パラメータの情報が消されている。 また、3 行目で配列の共変性により stringListsobjects に代入されている。 これより、4 行目において、Integer 型の要素からなるリストが String 型の要素からなるリストに代入されてしまっている。 こうなると、5 行目で Integer から String への誤ったキャストが起こり、ClassCastException が投げられる。 以上の処理が起きるのを防ぐために、 ジェネリック配列はコンパイルエラーとなる。

結論

以上のようなことがあるので、ジェネリックスを使いたいときは、List などのコレクション型を利用する方がよい。

参考文献

Effective Java 第2版