TypeVariable.getGenericDeclaration()不会返回我期望的类型

时间:2016-08-11 17:07:00

标签: java reflection

在下面的代码中,我希望nameBlackBox,因为这是complex字段的类型。但它返回Pair,这是另一个字段的类型simple

public class QuestionTest {
    abstract class BlackBox<TSimple, TComplex> {
        public TComplex complex;
        public TSimple simple;
    }

    abstract class Pair {
        public String one;
        public String two;
    }

    private String getFieldType(Class cls, String fieldName) throws NoSuchFieldException {
        Field field = cls.getField(fieldName);
        TypeVariable typeVariable = (TypeVariable) field.getGenericType();
        GenericDeclaration genDec = typeVariable.getGenericDeclaration();
        Class genCls = (Class) genDec;
        return genCls.getSimpleName();
    }

    @Test
    public void Test() throws NoSuchFieldException {
        BlackBox<Integer, Pair> blackBox =
                new BlackBox<Integer, Pair>() {};

        blackBox.complex = new Pair() {};
        blackBox.complex.one = "Uno";
        blackBox.complex.two = "Duo";
        blackBox.simple = 3;

        String fieldTypeName = getFieldType(blackBox.getClass(), "complex");
        Assert.assertEquals("Pair", fieldTypeName);
    }
}

哪里是我的错?

1 个答案:

答案 0 :(得分:1)

关于你的代码片段的重要部分是你在这里使用匿名子类:

    BlackBox<Integer, Pair> blackBox =
            new BlackBox<Integer, Pair>() {};

这会导致Java保留一些否则会丢失的泛型类型信息。您可以使用getGenericSuperclass()检索它:

    ParameterizedType genericSuperclass = (ParameterizedType) blackBox.getClass().getGenericSuperclass();
    Class<?> secondTypeArgument = (Class<?>) genericSuperclass.getActualTypeArguments()[1];
    String fieldTypeName = secondTypeArgument.getSimpleName();

对于一般解决方案,您必须在getActualTypeArguments()数组中找到字段的实际类型的索引:

private String getFieldType(Class cls, String fieldName) throws NoSuchFieldException {
    Field field = cls.getField(fieldName);
    TypeVariable fieldTypeVariable = (TypeVariable) field.getGenericType();

    int typeVariableIndex = -1;
    TypeVariable[] superclassTypeVariables = cls.getSuperclass().getTypeParameters();
    for (int i = 0; i < superclassTypeVariables.length; i++) {
        TypeVariable classTypeVariable = superclassTypeVariables[i];
        if (classTypeVariable.equals(fieldTypeVariable)) {
            typeVariableIndex = i;
            break;
        }
    }

    ParameterizedType genericSuperclass = (ParameterizedType) cls.getGenericSuperclass();
    Class<?> actualType = (Class<?>) genericSuperclass.getActualTypeArguments()[typeVariableIndex];
    return actualType.getSimpleName();
}