なんとなく連載になっている、Javaのジェネリクスシリーズの第3弾です。
今回は前回取りこぼしたところをまとめます。
型互換のコンパイルエラーを出す仕組み
<? extends ~>や<? super ~>
といった型指定をしたListを作った場合にadd()ができないことがあるよ、ということを話しましたが、
コンパイラはどうやって引数に整合性が保てない型がくると困るメソッドを特定しているのでしょう?
どうやってadd()にコンパイルエラーを出し、get()は許しているのでしょう?
使えなくなるメソッドと使えるメソッドの差は一体?
原理としては、メソッドの引数の部分に型パラメータが用いられている場合、型互換でエラーが起きます。
戻り値の部分に型パラメータが用いられている場合は型互換のエラーはおきません。
ですから、自分で作ったクラスであっても、どんなメソッド名にしていても、
引数に型パラメータが使われていて型互換の問題が起きる場合は警告してくれます。
種を明かせば簡単な仕掛けですね。
staticメソッドの型パラメータ
java.util.CollectionsクラスにはコレクションAPI向けの便利なstaticメソッド郡が定義されていますが、
これらのstaticなメソッドにもジェネリクスの型パラメータが利用されています。
非staticな場合の型パラメータ指定は宣言型やコンストラクタの時点で設定することはよくご存知でしょう。
staticメソッドの場合の型パラメータの指定方法はちょっと違うので知らないと嵌ります。
List<String> list = new ArrayList<String>();
Collections.<String>sort(list);
といった記法になります。メソッドの手前の"."の直後に型を記述します。
ちなみにメソッドの宣言側はこのような記述になります。
public static <E> void hoge() {
ここではvoidとしていますが、要するに戻り型の手前で
型パラメータのプレースホルダを記述します。
実はstaticメソッドじゃなくても使える
実はこのメソッドのローカルの型パラメータはstaticメソッド以外にも使えます。
具体的にはインスタンスメソッドとコンストラクタです。宣言が以下のようになります。
/**
* コンストラクタに型パラメータを指定した例
* @param <T> 型パラメータ
* @param param 引数
*/
public <T> Hoge(T param) {
}
/**
* インスタンスメソッドに型パラメータを指定した例
* @param <T> 型パラメータ
* @param param 引数
*/
public <T> void piyo(T param) {
}
これらの宣言がされているコンストラクタ、メソッドを適切に呼び出すには以下のような記述になります。
// ローカル型パラメータのあるコンストラクタを呼び出す例
Hoge hoge = new <String>Hoge("test");
// ローカル型パラメータのあるインスタンスメソッドを呼び出す例
hoge.<Integer>piyo(new Integer(3));
基本的にはstaticメソッドの場合と同じです。手前に型パラメータを記述するのですね。
なお、コンストラクタについてはclassに型パラメータがあると
// classに型パラメータがありローカル型パラメータもあるコンストラクタを呼び出す例
Hoge<Integer> hoge = new <String>Hoge<Integer>("param");
といったように、コンストラクタ名の前後に型パラメータを指定することになります。ちょっと面白いですね。
投稿日時 : 2007年8月5日 16:12