Java中的拆箱和反思?

时间:2010-07-08 15:15:18

标签: java reflection

我在我正在编写的模型中有一个带有签名public void setFoo(int newFoo)的方法。我正在使用以下代码从我的控制器中调用它:

protected void setModelProperty(String propertyName, Object newValue) {

    for (AbstractModel model: registeredModels) {
        try {
            Method method = model.getClass().
                getMethod("set"+propertyName, new Class[] {
                                                  newValue.getClass()
                                              }
                         );
            method.invoke(model, newValue);

        } catch (Exception ex) {
            //  Handle exception.
            System.err.println(ex.toString());
        }
    }
}

调用controller.setModelProperty("Foo",5);这样的方法会导致抛出异常:java.lang.NoSuchMethodException: foo.bar.models.FooModel.setFoo(java.lang.Integer) - 看起来int被装箱为Integer,而不是5匹配setFoo的签名。

有没有办法说服这个反射代码传递public void setFoo(Integer newFoo)(或我传入的任何int)作为一个整数,没有拳击?或者我必须在我的模型和unbox中明确创建{{1}},然后调用原始的setFoo?

6 个答案:

答案 0 :(得分:4)

您可以将setModelProperty专门用于您希望使用的任何基元:

protected void setModelProperty(String propertyName, int newValue) { /* ... */ }

或者,您可以在newValue上使用instanceof来检查盒装基元:

Class[] classes;
if (newValue instanceof Integer) {
  classes = new Class[] { int.class };
} else if (newValue instanceof Double) {
  /* etc...*/
} else {
  classes = new Class[] {newValue.getClass() };
}

或者最后,如果您拥有setFoo的源代码,您可以将其更改为使用盒装的Integer而不是int - 开销通常可以忽略不计。

答案 1 :(得分:2)

  

有没有办法说服这个   反射代码传递5(或   无论我传入什么int)作为整数,   没有拳击?

当您的方法签名显示Object newValue时,因为int永远不会是Object。保持方法通用的一种方法是让调用者明确地传入类型,即:

protected void setModelProperty(String propertyName, Object newValue, Class type) {

或者,您可以测试newValue的类型以查看它是否是原始包装器,并且在这种情况下查找该方法的原语和包装版本。但是,当用户传入null时,这将无效。实际上,在这种情况下,该方法根本不起作用......

答案 2 :(得分:1)

当调用setModelProperty()时,newValue被装箱为整数。这是它被调用的唯一方式; 'int'不是Object的实例。 newValue.getClass()返回“Integer”,因此对getMethod()的调用失败。

如果你想在这里使用原语,你需要一个特殊版本的setModelProperty。或者,您可以编写方法setFoo(Integer)。

或者更普遍的是你可以写:

if (newValue.getClass()==Integer.class) {
  // code to look for a method with an int argument
}

答案 3 :(得分:0)

问题不在于调用,而在于获取方法,因为您使用的Integer.class与int.class不同。

如果第一个方法失败,你可以通过第二次调用get方法来修复它:

protected void setModelProperty(String propertyName, Object newValue) {

    for (AbstractModel model: registeredModels) {
        Method method = null;
        try {
            method = model.getClass().
                 getMethod("set"+propertyName, new Class[] {
                                                  newValue.getClass()
                                               }
                         );
        } catch (Exception ex) {
            try {
                if (canBoxPrimitive(newValue.getClass()) {
                    method = model.getClass().
                           getMethod("set"+propertyName, new Class[] {
                                                  primitiveClass(newValue.getClass())
                                               }
                }
            }
            catch (Exception ex) {
                // handle it
            }
        }

        method.invoke(model, newValue);
   }
}

有关编码函数的选项: boolean canBoxPrimitive(Class) Class primitiveClass(Class)你可以看看这里:Dynamically find the class that represents a primitive Java type

答案 4 :(得分:0)

将完成Outoboxing,但您正在寻找错误的方法。参数类型数组不正确。对于int,类型将是Integer.TYPE而不是Integer.class。

尝试使用以下内容以使其工作,无论参数类型如何(outoboxing都会这样做):

protected void setModelProperty(String propertyName, Object newValue) {

    for (AbstractModel model: registeredModels) {
        try {
            Method method = findSetter(model.getClass(), propertyName);
            method.invoke(model, newValue);

        } catch (Exception ex) {
            //  Handle exception.
            System.err.println(ex.toString());
        }
    }
}

private Method findSetter(Class<?> type, String propertyName) {
    for (Method methos : type.getMethods()) {
        if (method.getName().equalsIgnoreCase("set" + propertyName) && method.getParameterTypes().length == 1) {
            return method;
        }
    }
    throw new NoSuchMethodError("No setter for " + propertyName);
}

答案 5 :(得分:-1)

你试过吗

Integer.valueOf(5)以整数形式传递5而不是int?