我目前正在开发一个小型框架来收集OSGi系统中的指标。 它的核心是注释@Metric,表示服务的给定方法在被询问时可以提供度量(例如数值)。
这些方法看起来像:
@Metric
public int getQueueSize() {...}
或
@Metric
public double getAvgTaskTime() {...}
我正在使用反射检查服务实现类并注册使用@Metric
注释的方法。作为一个完整性检查,我正在检查该方法确实提供了一个数值。我试过这个并且失败了:
for (Method method: metricSource.getClass().getMethods()) {
if (method.isAnnotationPresent(Metric.class) && Number.class.isAssignableFrom(method.getReturnType()) {
// add method for later process
}
然后,稍后在处理器上,我会这样做:
Number value = (Number) method.invoke(target, obj[]);
事实证明,对于原始类型,你会得到例如int.class
并且这不能分配给Number.class,而盒装类型Integer.class则是。该死的。继续前进。
然后我创建了一个Map<Class<?>, Extractor>
,其中Extractor接受一个类并将参数强制转换为该类:
public NumberExtractor(Class<? extends Number> clazz) {
this.clazz = clazz;
}
public double extract(Object val) {
Number nbr = clazz.cast(val);
return nbr.doubleValue();
}
}
面对之前的观察,我添加了一个这样的条目:
extractorMap.put(int.class, new NumberExtractor(int.class));
但这也不起作用。它给出了一个运行时类转换异常,说Integer.class无法转换为int。另请注意,编译器不会在new NumberExtractor(int.class)
上投诉,让边界检查Class<? extends Number>
传递int.class
最后,这种组合起作用了:
extractorMap.put(int.class, new NumberExtractor(Integer.class));
这里发生了什么? Reflection说对象的返回类型(int.class)不能赋值给Number.class,但是当我继续调用方法时,我实际上得到了一个Integer.class? WhiskeyTangoFoxtrot?!
我想知道除了维护地图之外是否有另一种解决这个问题的方法 - &gt;整数,整数 - &gt;整数,浮点数 - &gt; Float,Float - &gt;浮动? (现在已经完成了,所以这是为了学习)
拳击和类型信息的行为在这里似乎并不一致。
有人可以对此发表一些看法吗?
答案 0 :(得分:10)
Reflection说对象的返回类型(int.class)不能赋值给Number.class,但是当我继续调用方法时,我实际上得到了一个Integer.class?
绝对。反射API不能可能返回实际的int
,因此它会将值设置为Integer
。它还能做什么?
必须使用不这一事实会将int
的可分配性更改为Number
。看看docs for isAssignableFrom
:
如果此Class对象表示基本类型,则如果指定的Class参数恰好是此Class对象,则此方法返回true;否则返回false。
所以它的行为完全符合文档。
是的,这对我来说是对的。或者只是对原始数字类型使用我想知道除了维护地图之外是否有另一种解决这个问题的方法 - &gt;整数,整数 - &gt;整数,浮点数 - &gt; Float,Float - &gt;浮动? (现在已经完成了,所以这是为了学习)
Set<Class>
而不是显式映射。