9

我目前正在开发一个小型框架来收集 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[]);

事实证明,对于原始类型,您会得到 egint.class并且不能分配给 Number.class 而装箱类型 Integer.class 会。该死。继续。

然后我创建了一个Map<Class<?>, Extractor>where 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));

这里发生了什么?反射说对象(int.class)的返回类型不能分配给Number.class,但是当我继续调用方法时,我实际上得到了一个Integer.class?威士忌探戈狐步舞?!

我想知道除了维护 int -> Integer、Integer -> Integer、float -> Float、Float -> Float 的 Map 之外,是否还有其他方法可以解决这个问题?(现在已经完成了,所以这是为了学习)

装箱和类型信息的行为在这里似乎不一致。

有人可以对此有所了解吗?

4

1 回答 1

10

反射说对象(int.class)的返回类型不能分配给Number.class,但是当我继续调用方法时,我实际上得到了一个Integer.class?

绝对地。反射 API不可能返回一个实际的int,所以它把值装在一个Integer. 它还能做什么?

它必须装箱的事实不会将可分配性从intto改变Number。查看文档isAssignableFrom

如果此 Class 对象表示原始类型,则如果指定的 Class 参数正是此 Class 对象,则此方法返回 true;否则返回false。

所以它的行为完全符合文档。

我想知道除了维护 int -> Integer、Integer -> Integer、float -> Float、Float -> Float 的 Map 之外,是否还有其他方法可以解决这个问题?(现在已经完成了,所以这是为了学习)

是的,这听起来对我来说是正确的。或者只是有一个Set<Class>原始数字类型而不是显式映射。

于 2012-08-01T17:50:57.900 回答