総称型を使う
総称は、コレクションクラスのインスタンスに、特定の種類のインスタンスだけ収められるようにする機能です。これは、
ArrayList<タイプ> 変数 = new ArrayList<タイプ>();
このような形でインスタンスを作成します。こうすることで、<>に指定したタイプのオブジェクトしか入れることができなくなるのです。では、実際に使ってみましょう。
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add("Hello");
list.add("Welcome");
list.add("to");
list.add("Java");
list.add(123);
for(Object obj:list){
String s = (String)obj;
System.out.println(s);
}
}
例えば、こんなプログラムがあったとしましょう。Stringの値をいくつか入れ、それをあとで取り出して表示するものですね。addでStringを追加し、forで値を取り出していきます。ArrayListから値を取り出すときは、すべてObjectインスタンスになります。これは、どんな種類のオブジェクトが入っているかわからないので、すべてをObjectとして取り出し、必要に応じてもとのクラスにキャストして戻して使うようになっているのですね。
これはこれでちゃんと動きます。が、問題なのは、このaddの中に、String以外のものをaddするような文が紛れ込んでいても、プログラムはちゃんとコンパイルできてしまう、という点です。例えば、ここでは最後にlist.add(123);というのがあります。これでint値(実際には、Integerインスタンス)を追加しています。が、これでもちゃんとコンパイルできてしまいます。
が、実際にプログラムを実行すると、String s = (String)obj;の部分で例外が発生し、動きません。Integerの値をStringにキャストしようとしてエラーになってしまうのです。そこで、総称型の出番となります。
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("Hello");
list.add("Welcome");
list.add("to");
list.add("Java");
for(String obj:list){
System.out.println(obj);
}
}
ここでは、ArrayListを作成するのに、<String>という総称型を指定しています。そうするとどうなるか? まず、このプログラムは、コンパイルできなくなります。list.add(123);のところでコンパイルエラーになるのです。listには、String以外のものはaddできなくなってしまい、それ以外のものをaddしていると、そこでエラーが起こり、プログラムは絶対にコンパイルできません。
list.add(123);の文を削除すると、プログラムはコンパイルできるようになります。総称型により、指定した種類のオブジェクトしか扱えなくなっていることがよくわかりますね。また、総称型で指定をすると、オブジェクトを取り出したとき、Objectのインスタンスではなく、総称型で指定した種類のインスタンスとして取り出せるようになります。このため、取り出したオブジェクトをキャストする必要がなくなるのです。