先日ジェネリクスで引っ掛かった点をメモ。
自己言及するジェネリクスで述べたような具象型に具象型自身の型を扱わせることをもくろんだ型を作った場合の話。
public class GenericsTest {
static abstract class S<T extends S<T>> {}
static class A extends S<A> {}
static class B extends A {}
static class C extends S<A> {}
static class X1<T extends S<T>>{}
static class X2<T extends S<?>>{}
static class X3<T extends S<? super T>>{}
public static void main(String[] args) {
X1<A> x1A; // OK
X1<B> x1B; // NG
X1<C> x1C; // NG
X2<A> x2A; // OK
X2<B> x2B; // OK
X2<C> x2C; // OK
X3<A> x3A; // OK
X3<B> x3B; // OK
X3<C> x3C; // NG
}
}
Sが親となるクラスで<T extends S<T>>という境界をもつジェネリクス型変数Tを持ちます。
サブクラスであるAはこのTにA自身を渡すことで、Sクラス中にT型で宣言した部分をA型にすることができるのですね。
そのA型を継承したクラスBを考えた場合、BはS<A>を継承しているのでB extends S<A>ということになります。
なのでX1の境界<T extends S<T>>に合致しません。
こうした型を受け入れれるように規制を緩めたのがX2で<T extends S<?>>としています。
この場合、穴ができてCのようなAのサブクラスでもないのにSの型変数TにAを渡したような歪なクラスを宣言した場合に許容されてしまいます(x2C部分)。
クラスS中に表現されるTを具象型自身にするという趣旨からすればこのような歪な型は許容したくありません。
T型の戻り値のメソッドでreturn this;とか書きたいわけです。
なので正確に型を表現するとしたならば<T extends S<? super T>>とします。
これでAはもちろん、AのサブクラスであるBも許容され、歪なCは弾くことができます。
投稿日時 : 2009年1月23日 23:45