先のエントリの続きです。ちょっと調べたらわかったので。
とりあえず、こんなクラスを用意して
class GenericClass<T> { } class StringedClass extends GenericClass<String> { } class NumberedClass extends GenericClass<Number> { } interface GenericInterface<T> { } class StringedImpl implements GenericInterface<String> { } class NumberedImpl implements GenericInterface<Number> { }
こんなコードを用意して実行すると
import java.lang.reflect.*; public class GenericsExtends { public static void main(String[] args) { Type type; type = StringedClass.class.getGenericSuperclass(); System.out.println( ((ParameterizedType)type).getActualTypeArguments()[0] == String.class); type = NumberedClass.class.getGenericSuperclass(); System.out.println( ((ParameterizedType)type).getActualTypeArguments()[0] == Number.class); for (Type t : StringedImpl.class.getGenericInterfaces()) { if (ParameterizedType.class.isInstance(t) && ParameterizedType.class.cast(t).getRawType() == GenericInterface.class) { System.out.println( ParameterizedType.class.cast(t).getActualTypeArguments()[0] == String.class); } } for (Type t : NumberedImpl.class.getGenericInterfaces()) { if (ParameterizedType.class.isInstance(t) && ParameterizedType.class.cast(t).getRawType() == GenericInterface.class) { System.out.println( ParameterizedType.class.cast(t).getActualTypeArguments()[0] == Number.class); } } } }
実行結果として、「true」が4つ表示されます。
class StringedClass extends GenericClass<String> { }
などの、「String」などの部分が字面ではなくて、型情報として取得できています。
ポイントは、
class StringedClass<String> extends GenericClass<String> { }
みたいにサブクラスもパラメータ化しないことと。これをやってしまうと、ParameterizedType#getActualTypeArgumentsから返る結果がTypeVariableになってしまって、具体的な型が取れなくなります。
それからTypeを取得する時は、親がクラスなのかインターフェースなのかに応じて、Class#getGenericSuperclassおよびClass#getGenericInterfacesを使用すること。
そう考えると、先の例はちょっとマヌケな感じでしたね…。