Java中字段类型实现的接口通用信息
Posted
技术标签:
【中文标题】Java中字段类型实现的接口通用信息【英文标题】:Generic information about interface implemented by field type in Java 【发布时间】:2021-11-09 09:43:05 【问题描述】:假设我们有一个类型CustomMap<A, B>
,它扩展了CommonMap<C, D>
,而Map<E, F>
又实现了Map<E, F>
。
自然会期望A == C == E
,但并非总是如此 - 例如,您可以让CustomMap<V>
实现Map<String, V>
。
问题是,假设我有一个Field
,而field.getType()
是实现Map<K, V>
的某个接口或类。类型本身可能是非泛型的,也可能是泛型的,但具有不同于<K, V>
的泛型签名等。我如何使用反射获得Map
的K
和V
类型参数?
【问题讨论】:
你不能。 Java 有type erasure,这意味着类型参数在编译代码时会被删除。结果类型是最具体的绑定类型,可能是Object
。
这不正确,类型信息保留在字段中,您可以通过field.getGenericType()
获取。
这是可能的,但是正确处理所有极端情况的代码会很糟糕。例如,字段的类型可以引用声明类的类型变量,其边界引用声明类的外部类的类型变量。当遍历字段类型的超类型层次结构时,可能存在类似的极端情况,以用它们的实际参数替换类型变量。另外,没有公共实现类型或工厂方法来生成对象来表达结果(即在找到实际的X
和Y
之后为Map<X,Y>
构造ParameterizedType
)。
这有点麻烦,但在实践中完全可行。我将发布我所学到的要点。
【参考方案1】:
似乎必须编写爬取类型信息的代码,记住哪个类型对应于类型参数名称,然后进行替换。代码可能会根据具体情况而有所不同,例如类/接口等,但其核心是:
// 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()
,直到你首先找到你想要的类型。如果在任何地方使用原始类型,可能会出现极端情况。
【讨论】:
类型并不总是ParameterizedType
。想想class StringMap implements Map<String,String>
或现实生活中的例子class Properties implements Map<Object,Object>
。在这些情况下,类型只是 Class
,但 getGenericSuperclass()
/ getGenericInterfaces()
仍然可以工作(换句话说,它与原始类型无关)。此外,替换也可以递归地应用于类型参数,想想class StringMap extends MultiMap<String,String> class MultiMap<K,V> implements Map<K,List<V>>
(但没有API来创建代表List<String>
的Type
对象)......
您的代码中没有递归。在我的implements Map<K,List<V>>
示例中,只有一个instanceof TypeVariable
评估为false
,因为List<V>
不是类型变量,而是参数化类型(指的是您的代码不能用其实际参数替换的类型变量) .
它无法处理我的示例。点。
我不知道这条评论是什么意思。你在这里问了一个问题,我在this comment 告诉你,处理所有情况的正确解决方案非常复杂。现在,您发布了一个不完整的解决方案,该解决方案在更简单的情况下都失败了,甚至没有接近该评论中提到的极端情况,并且拒绝承认它是不完整的。这对任何人有什么帮助?
我没有问任何问题。我告诉过你,你的问题并没有被这个“答案”回答。以上是关于Java中字段类型实现的接口通用信息的主要内容,如果未能解决你的问题,请参考以下文章