我正在尝试检查Map<String, T>
是否包含Double或Integer类型的Objects(T)。
我不想使用地图中的实际对象来检查类,因为它不确定Map是否包含对象。
我可以通过执行以下操作来实现此目的(假设该字段包含Map):
ParameterizedType type = (ParameterizedType) field.getGenericType();
isNumeric(type);
/**
* @param type
* @return Returns true if type is numeric
*/
private static boolean isNumeric(ParameterizedType type) {
return type.getActualTypeArguments()[1].toString().equals("? extends java.lang.Number");
}
这对我来说已经足够了,但它并不像是一个干净的解决方案。
但是,我可以检索getActualTypeArguments()[1]
的类型
通过执行以下操作:
Type typeOfSecondGeneric = type.getActualTypeArguments()[1]; // equals '? extends java.lang.Number'
我无法使用Number.class.isAssignableFrom(typeOfSecondGeneric); // Class expected
在我研究了一下之后,我没有想出比做String比较更好的解决方案。
我出错了什么?
非常感谢帮助!
答案 0 :(得分:1)
临时解决方案可能是这样的:
private static boolean isNumericValue(ParameterizedType t) {
return isSubclassOf(t.getActualTypeArguments()[1], Number.class);
}
private static boolean isSubclassOf(Type t, Class<?> clazz) {
if (t instanceof Class<?>)
return clazz.isAssignableFrom((Class<?>) t);
if (t instanceof ParameterizedType)
return isSubclassOf(((ParameterizedType) t).getRawType(), clazz);
Type[] bounds = null;
if (t instanceof TypeVariable<?>)
bounds = ((TypeVariable<?>) t).getBounds();
if (t instanceof WildcardType)
bounds = ((WildcardType) t).getUpperBounds();
if (bounds != null && bounds.length > 0)
return isSubclassOf(bounds[0], clazz);
return clazz == Object.class;
}
这个简短的例子不处理接口类型或通用数组类型。在实际的子类型规则方面,它还远没有完成。
如果确实需要这样的话,我认为更好的解决方案是使用Guava TypeToken
:
private static final TypeToken<Map<?, ? extends Number>> T =
new TypeToken<Map<?, ? extends Number>>() {};
private static boolean isNumericValue(ParameterizedType t) {
return T.isSupertypeOf(t);
}
那就是说,我并不是所有人都相信你确实需要这个。这看起来像XY problem,您可能会更好地询问有关您尝试解决的问题的问题,而不是您尝试的解决方案。这种代码在你的程序被束缚到使用它之后会变成一个巨大的痛苦,特别是如果它普遍存在的话。
答案 1 :(得分:1)
此信息在运行时丢失,因此通常您无法确定T
到底是什么。
此一般规则的例外仅限于地图对象类本身对该T
具有更具体约束的情况。例如:
class MyDoubleMap<K> extends Map<K, Double> {
...
}
...
Map<String, Double> standard = new HashMap<>();
Map<String, Double> doubles = new MyDoubleMap<>();
Map<String, Double> annonDoubles = new HashMap<>() {};
使用standard
任何反射技巧都无法恢复超过T
,并且它可以是任何扩展Object
的内容。
但是对于其他两个案例doubles
和annonDoubles
,其他答案中包含的反映代码应该Double
分配到T
。
使用doubles
应该很容易看到该信息应该通过反射提供,因为它是MyDoubleMap
声明的组成部分。也许
annonDoubles
稍微不那么明显,但实际上跟踪{}
它实际上是在宣布匿名
扩展HashMap<String, Double>
的内部类,因此可以通过反射恢复T
(以及K
)的此类信息。