在下面的代码中,我希望name
为BlackBox
,因为这是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);
}
}
哪里是我的错?
答案 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();
}