我有以下的类结构:
public class GenClass<T> {
public T elem;
}
我这样使用它:
public class Test {
public GenClass<UUID> data;
现在我想使用data(Test.class.getField("data")
)的Field对象获取元素的类型但是当我使用getType
检索类时,泛型信息被剥离。
我如何将通用信息从getGenericType
映射到类对象以检索具有正确类型的字段?
编辑:由于有一些误解,我试图澄清我的问题。考虑这个例子:
public class AClass<T, Q> {
public Q elem;
// some other code using T...
}
public class BClass<T, Q> {
public T elem;
// some other code using Q...
}
现在我想要一个函数来获取元素的类:
public class Test {
public AClass<UUID, String> a;
public BClass<Integer, Float> b;
void do() throws Exception {
Field aField = Test.class.getField("a");
Field bField = Test.class.getField("b");
getType(aField, "elem"); // should return String.class
getType(bField, "elem"); // should return Integer.class
}
Class<?> getType(Field f, String classField) {
// ???
}
}
我需要如何实现getType
来获得我想要的结果?
您有Type
对象对应于您的字段data
,从调用getGenericType
。
Type t = f.getGenericType(); // f is your Field
Type
接口及其实现代表了这里可能出现的类型的不同情况。因为data
的类型是GenClass<UUID>
,用类型参数参数化,所以这里返回的Type
实际上是ParameterizedType
。
ParameterizedType pt = (ParameterizedType) t;
通常可以有多个泛型类型参数,但这里只有一个。调用ParameterizedType
的getActualTypeArguments
方法
Type parameter = pt.getActualTypeArguments()[0];
是的,我们有另一个Type
实例,但这个实例代表Field
的泛型类型参数,而不是Field
本身。因为您在Test
类中提供了一个类类型,所以这个Type
只不过是一个普通的Class
—UUID.class
。
System.out.println(parameter instanceof Class);
System.out.println(parameter == UUID.class);
输出:true
true
好的,那么您需要做的是获取a/b字段的原始类型的类型参数,以及ParameterizedType的实际类型参数。然后可以将原始类型参数与您感兴趣的A/b类上的elem字段进行匹配,然后使用它来解析/匹配到实际类型(数组对齐)。
public class TestGenerics {
public AClass<UUID, String> a;
public BClass<Integer, Float> b;
void getFieldTypes() throws NoSuchFieldException, SecurityException {
Field aField = TestGenerics.class.getField("a");
Field bField = TestGenerics.class.getField("b");
Class<?> aFieldElem = getType(aField, "elem"); // should return String.class
Class<?> bFieldElem = getType(bField, "elem"); // should return Integer.class
System.out.println("a field, elem field type: " + aFieldElem.getSimpleName());
System.out.println("b field, elem field type: " + bFieldElem.getSimpleName());
}
Class<?> getType(final Field f, final String classField) throws NoSuchFieldException, SecurityException {
Type genericType = f.getGenericType();
//going to assume this. In reality you'd want to do an instanceof first
ParameterizedType pt = (ParameterizedType) genericType;
Class<?> rawType = (Class<?>) pt.getRawType();
Type[] actualTypeParams = pt.getActualTypeArguments();
TypeVariable<?>[] rawTypeParams = rawType.getTypeParameters();
Field classFieldOnF = rawType.getField(classField);
genericType = getResolvedType(classFieldOnF.getGenericType(), rawTypeParams, actualTypeParams);
//same here, you'd need to do an instanceof first
return (Class<?>) genericType;
}
private Type getResolvedType(final Type genericType, final Type[] rawTypeParams, final Type[] actualTypes) {
for (int i = 0; i < rawTypeParams.length; i++) {
if (genericType == rawTypeParams[i]) return actualTypes[i];
}
return genericType;
}
public static void main(final String[] args) throws NoSuchFieldException, SecurityException {
TestGenerics test = new TestGenerics();
test.getFieldTypes();
}
}
输出是:
a field, elem field type: String
b field, elem field type: Integer