调用最接近的拟合方法

时间:2010-02-09 00:54:03

标签: java reflection dynamic-languages

作为开发一个小ScriptEngine的一部分,我反思地调用java方法。脚本引擎的调用为我提供了方法名称和参数数组的对象。要调用方法,我尝试通过调用Class.getMethod(名称,参数类型)来解决它 但是,只有当参数的类和Method预期的类相同时,才能使用它。

Object o1 = new Object();
Object out = System.out;
//Works as System.out.println(Object) is defined
Method ms = out.getClass().getMethod("println",o1.getClass());
Object o2 = new Integer(4);
//Does not work as System.out.println(Integer) is not defined
Method mo = out.getClass().getMethod("println",o2.getClass());

我想知道是否有一种“简单”的方法来获得正确的方法,如果可能的话,最适合参数类型,或者我必须自己实现。

最贴合的是:

Object o1 = new Integer(1);
Object o2 = new String("");
getMethod(name, o1.getClass())//println(Object)
getMethod(name, o2.getClass())//println(String)  

更新
澄清我需要的东西: 脚本引擎是我在空闲时间写的一个小项目,因此我没有必须遵循的严格规则。因此我认为选择从Engine调用的方法与java编译器在编译时仅使用动态类型而不是Object的静态类型选择方法的方式相同。(有或没有自动装箱)
这是我首先希望Class.getMethod()解决的问题。但是Class.getMethod()需要与Method声明的参数类型完全相同的类,使用子类将导致没有这样的方法Exception。这可能是有充分理由发生的,但是这个方法对我来说没用,因为我事先并不知道哪种参数类型适合。
另一种方法是调用Class.getMethods()并遍历返回的数组并尝试查找拟合方法。然而,如果我不想采用我遇到的第一个“好”方法,那将会很复杂,所以我希望现有的解决方案至少可以处理:

  • 最接近:如果arg.getClass()== 子类和方法m(超类), m(Subclass)然后调用m(Subclass)
  • 变量参数: System.out.printf(String,String ...)

支持自动装箱也很不错 如果无法解析调用,则可能抛出异常(ma(String,Object),ma(Object,String),args = String,String)
(如果你在这里做到了,感谢花时间阅读它: - ))

3 个答案:

答案 0 :(得分:2)

我建议您使用getMethods()。它返回所有公共方法的数组(Method[])。

这里最重要的是:
如果类声明了多个具有相同参数类型的公共成员方法,则它们都包含在返回的数组中。

您需要做的是使用此数组中的结果确定哪一个(如果有的话)是最接近的匹配项。由于最接近的匹配应该在很大程度上取决于您的要求和具体应用,因此自行编码是有意义的。


示例代码说明了如何执行此操作的一种方法:

public Method getMethod(String methodName, Class<?> clasz)
{
    try
    {
        Method[] methods = clasz.getMethods();
        for (Method method : methods)
        {
            if (methodName.equals(method.getName()))
            {
                Class<?>[] params = method.getParameterTypes();
                if (params.length == 1)
                {
                    Class<?> param = params[0];
                    if ((param == int.class) || (param == float.class) || (param == float.class))
                    {
                        //method.invoke(object, value);
                        return method;
                    }
                    else if (param.isAssignableFrom(Number.class))
                    {
                        return method;
                    }
                    //else if (...)
                    //{
                    //    ...
                    //}
                }
            }
        }
    }
    catch (Exception e)
    {
        //some handling
    }
    return null;
}

在此示例中,getMethod(String, Class<?>)方法将返回仅包含一个intfloatdouble或超类{{}的参数的方法1}}。

这是一个基本的实现 - 它返回适合该法案的第一种方法。您需要扩展它以创建匹配的所有方法的列表,然后根据某种标准对它们进行排序,并返回最佳匹配方法。

然后,您可以通过创建更通用的Number方法来进一步处理它,以处理更多可能的“近似匹配”方案,甚至可能包含多个参数

HTH


编辑:正如@finnw指出的那样,使用Class#isAssignableFrom(Class<?> cls)时要小心,因为它有其局限性,就像我在示例代码中一样,单独测试getMethod(String, Class<?>)对象的原语。

答案 1 :(得分:2)

答案 2 :(得分:1)

AFAIK,没有简单的方法来做这种事情。当然,标准Java类库中没有任何内容可以做到这一点。

问题在于没有单一的“正确”答案。您需要考虑所有用例,确定“正确的方法”应该是什么,并相应地实现您的反射代码。