代码之家  ›  专栏  ›  技术社区  ›  josefx

调用最近拟合方法

  •  5
  • josefx  · 技术社区  · 15 年前

    作为开发小型脚本引擎的一部分,我反射性地调用Java方法。脚本引擎的调用为对象提供了方法名和参数数组。要调用方法,我试图通过调用class.getmethod(name,参数类型)来解决它。
    但是,只有当参数的类和方法预期的类相同时,这才有效。

    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)  
    

    更新:
    为了澄清我需要什么: 脚本引擎是我在空闲时间编写的一个小项目,因此我不需要遵循任何删除规则。因此,我认为从引擎调用的方法与Java编译器在编译时选择方法的方式相同,只有动态类型而不是静态类型的对象才能工作。(有或没有自动装箱)
    这是我第一次希望class.getmethod()能够解决的问题。但是class.getmethod()需要与方法声明的参数类型完全相同的类,使用子类将导致无此类方法异常。这可能是有充分理由的,但这使得方法对我来说毫无用处,因为我事先不知道哪种参数类型适合。
    另一种方法是调用class.getmethods()并遍历返回的数组,然后尝试找到一个合适的方法。然而,如果我不只是想采用我遇到的第一个“好”方法,这将很复杂,因此我希望有一个现有的解决方案,至少可以处理:

    • 最近匹配:if arg.getClass()。== 子类和方法M(超类) m(子类),然后调用m(子类)
    • 变量参数: system.out.printf(字符串,字符串…)

    支持自动氧化也不错。
    如果无法解析调用,则可能引发异常(ma(字符串、对象)、ma(对象、字符串)、args=string、字符串)
    (如果你到了这里,感谢你花时间阅读它:-)

    3 回复  |  直到 15 年前
        1
  •  2
  •   finnw    15 年前

    正如其他人指出的那样,没有标准的方法可以做到这一点,所以您必须实现自己的过载解析算法。

    尽可能接近地遵循javac的过载解决规则可能是有意义的:
    http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#292575
    您可能可以忽略动态类型脚本语言的泛型,但是您仍然可以从 bridge methods 编译器自动生成的。

    需要注意的一些陷阱:

    • Class.isAssignableFrom 不知道自动扩展的原语转换,因为它们是编译器中实现的语法甜头;它们不出现在VM或类层次结构中。例如 int.class.isAssignableFrom(short.class) 退货 false .
    • 同样地 类.IsassignableFrom 不知道自动拳击。 Integer.class.isAssignableFrom(int.class) 收益率 .
    • Class.isInstance Class.cast 拿一个 Object 作为参数;不能将基元值传递给它们。他们还返回 对象 ,因此它们不能用于拆箱( (int) new Integer(42) 在Java源代码中是合法的 int.class.cast(new Integer(42)) 引发异常。)
        2
  •  2
  •   bguiz    15 年前

    我建议你用 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<?>) 方法将返回只有一个参数的方法,该参数是 int , float , double 或超类 Number .

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

    然后,您可以通过创建更通用的 GetMethod(字符串,类<?gt; 方法,以处理更多可能的“接近匹配”场景,甚至可能有多个参数

    高温高压


    编辑:正如@finnw指出的,使用时要小心 Class#isAssignableFrom(Class<?> cls) 由于它的局限性,正如我在示例代码中所做的那样,分别测试原语和 物体。

        3
  •  1
  •   Stephen C    15 年前

    阿法克,做这种事没有简单的方法。当然,标准Java类库中没有任何东西可以做到这一点。

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