CLOVER🍀

That was when it all began.

ジェネリクスで、親クラスに適用されたパラメータのClassを取得する

先のエントリの続きです。ちょっと調べたらわかったので。

とりあえず、こんなクラスを用意して

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を使用すること。

そう考えると、先の例はちょっとマヌケな感じでしたね…。