先日、Strategyのインスタンスをenumで扱うで取り上げたようにJavaのenumはメソッドを宣言することができます。JavaSE5.0でenumを追加する際、既存の型システムを利用して作られているため、Javaのenumはクラスなのです。
このenumの親クラスとなるのがjava.lang.Enumクラスなのですが、宣言が変わっていて、ジェネリクスの型パラメータが自身の拡張なのですね。
Enum<E extends Enum<E>>
これと同じような構造を持つクラスを作った場合、型安全にインスタンス化できません。
public class Hoge<H extends Hoge<H>> {
public static void main(String[] args) {
Hoge<Hoge<Hoge<...>>> hoge = new Hoge<Hoge<Hoge<...>>>()
}
}
型パラメータが再帰してしまうため、パラメータを与えることができない。これをずっと疑問に思っていたんですが、
自作のHEXのフレームワークの
リファクタリングをやっていて似たような構造が出来た時に、こうした自己言及するジェネリクスの使い方がわかりました。
この自己言及型のジェネリクスは継承する際に型パラメータに具象型を渡すことで実体化させることができます。
public class Hoge<H extends Hoge<H>> {
public H hoge() {
return null;
}
}
public class Piyo extends Hoge<Piyo> {
public static void main(String[] args) {
Piyo piyo = new Piyo();
Piyo piyo2 = piyo.hoge();
}
}
こんな感じですね。Hoge#hoge()メソッドは戻り型をHogeではなく、ジェネリクスでHとしています。
そのため、Hogeの継承型であるPiyoのhoge()メソッドは戻り型がHogeではなくてPiyo型になります。
サンプルソース中の強調部分を見てください。キャストしていませんよね。
もしもメソッドがHoge型を返すようにしているような場合では
Hogeの子クラスであるPiyo型をreturnすることはできますが、受け手、つまりメソッドの呼び出し元では
キャストを行わないと代入ができません。そして、そのキャストはダウンキャストであって型安全ではありません。
このように、自身のインスタンスを返すメソッドがあったとして、そのクラス(ここではHoge)継承された場合に
そのメソッドが継承した子クラス(ここではPiyo)を返すようにすることができるのです。
これは、自信のインスタンスを直接返す他、自信の型をジェネリクスとして用いているメソッドなどを定義する場合にも使えます。
投稿日時 : 2008年5月25日 18:06