総称型について
先日、総称型を使ってメソッドを作ったんですが、いざ動かすと、ClassCastExceptionが!!
なぜだ!!!
ということで、総称型について、再度、勉強だ( ^ω^)
総称型って
要は汎用的に使える型?ということですかね。通常、javaなどの場合、型を厳密に宣言して、変数などを定義しますが、これだと、型違いの関数をいっぱい作成したりする必要があり、無駄が発生するケースがあるのでしょうね。
その代わりといってはなんですが、汎用的な型を使って、いろいろな型に1つの関数やクラスで対応しようとしているもののように見えます。
どうやって使うの?
シンプルな使い方としては、型の代わりにTとか書くらしいです。
たとえば、メソッドの場合、
public <T> T method(T param) {
System.out.println(param);
return param;
}
のように記述します。
<T>という記述が気になりますが、これがどうやら、型を指定する場所のようです。
呼び出し方は、以下のようになります。
t.<String>method("文字");
t.<Integer>method(1);
文字型と数値型を渡していますが、これで特に問題なく動きます。また、戻り値も<>内で指定した型として扱われます。
その為、以下のように書くとコンパイル時にエラーとなります。(なるんかな・・)
t.<String>method(1);
これはTがStringなのに、引数としてIntegerが渡っているためです。
実は、この<String>などは省略して、記述することも可能です。
t.method(1);
引数にTがあり、その値がIntegerなので、自動的に判断するんですかね。
どんな時に使うの
実際のところ業務アプリを作っている場合、そうそうお目にかかることはないと思います。たとえば、フレームワークを開発していてアプリ独自のクラスの処理をしないといけないケースなどは、これを使うと便利だと思います。
使う場合の問題点
もともとJavaはある程度、型に厳格な言語ですので、不用意に総称型を使うといろいろな弊害が発生します。(今回もそれに引っかかったので)
たとえば、以下のコードだと、コンパイルエラーにはなりませんが、実行時にエラーが発生します。
<呼び出し元>
String aaa = new String[10];
t.method2(aaa, 1, new String(""));
t.method2(aaa, 2, new Integer(1));
<呼び出し先>
public <T> void method2(T tlist , int i, T param) {
System.out.println(param);
try {
tlist[i] = param;
} catch (SecurityException e) {
e.printStackTrace();
}
}
2回目のmethod2を呼び出し段階で、String[]に数字を入れようとしてるのが分かると思いますが、総称型を使うことで、想定していないところで、このようなことが起きる可能性があります。※総称型を配列に使わないというのは、割と有名な話なのかな?
まとめ
総称型は、うまく使えれば、かなり役にたつ素晴らしい技術だと思います。
ただし、使いどころを間違えばあらぬバグを発生させたりするものでもあります。
使いどころに気を付けてうまく使っていきましょう^^