Java中字段类型实现接口的通用信息
Generic information about interface implemented by field type in Java
假设我们有一个类型 CustomMap<A, B>
扩展了 CommonMap<C, D>
又实现了 Map<E, F>
.
人们自然会期望 A == C == E
,但并非总是如此 - 例如,您可以使用 CustomMap<V>
实现 Map<String, V>
。
问题是,假设我有一个 Field
,field.getType()
是某个接口或 class 实现 Map<K, V>
。类型本身可能是非通用的,可能是通用的但通用签名不同于 <K, V>
,等等。我如何使用反射获得 Map
的 K
和 V
类型参数?
看来得写代码爬取类型信息,记住类型参数名对应的类型,然后进行代入。代码可能会根据具体情况有所不同,例如class/interface等,但其核心是:
// Contains mappings such as K -> Integer, V -> String
Map<String, Type> typeParameters = new HashMap<>();
ParameterizedType pType = (ParameterizedType) type;
// Actual type arguments of a specific parametrized type, e.g. <Integer, PARAM> -
// the latter is resolved against typeParameters map
Type[] typeArguments = pType.getActualTypeArguments();
cls = ((Class) ((ParameterizedType) type).getRawType());
// Named arguments of type as declared, e.g. <K, V>
TypeVariable<?>[] typeParamDecls = cls.getTypeParameters();
for (int i = 0; i < Math.min(typeParamDecls.length, typeArguments.length); i++) {
Type value;
if (typeArguments[i] instanceof TypeVariable) {
value = typeParameters.get(((TypeVariable<?>) typeArguments[i]).getName());
} else {
value = typeArguments[i];
}
typeParameters.put(typeParamDecls[i].getName(), value);
}
这需要递归地应用到 cls.getGenericSuperclass()
/ cls.getGenericInterfaces()
直到你首先找到你想要的类型。如果在任何地方使用原始类型,可能会出现边缘情况。
假设我们有一个类型 CustomMap<A, B>
扩展了 CommonMap<C, D>
又实现了 Map<E, F>
.
人们自然会期望 A == C == E
,但并非总是如此 - 例如,您可以使用 CustomMap<V>
实现 Map<String, V>
。
问题是,假设我有一个 Field
,field.getType()
是某个接口或 class 实现 Map<K, V>
。类型本身可能是非通用的,可能是通用的但通用签名不同于 <K, V>
,等等。我如何使用反射获得 Map
的 K
和 V
类型参数?
看来得写代码爬取类型信息,记住类型参数名对应的类型,然后进行代入。代码可能会根据具体情况有所不同,例如class/interface等,但其核心是:
// Contains mappings such as K -> Integer, V -> String
Map<String, Type> typeParameters = new HashMap<>();
ParameterizedType pType = (ParameterizedType) type;
// Actual type arguments of a specific parametrized type, e.g. <Integer, PARAM> -
// the latter is resolved against typeParameters map
Type[] typeArguments = pType.getActualTypeArguments();
cls = ((Class) ((ParameterizedType) type).getRawType());
// Named arguments of type as declared, e.g. <K, V>
TypeVariable<?>[] typeParamDecls = cls.getTypeParameters();
for (int i = 0; i < Math.min(typeParamDecls.length, typeArguments.length); i++) {
Type value;
if (typeArguments[i] instanceof TypeVariable) {
value = typeParameters.get(((TypeVariable<?>) typeArguments[i]).getName());
} else {
value = typeArguments[i];
}
typeParameters.put(typeParamDecls[i].getName(), value);
}
这需要递归地应用到 cls.getGenericSuperclass()
/ cls.getGenericInterfaces()
直到你首先找到你想要的类型。如果在任何地方使用原始类型,可能会出现边缘情况。