Java:运行时方法解析

15

我正在通过解释器进行代码的动态调用,但涉及到方法解析时,我开始陷入棘手和丑陋的领域,这些领域在JLS第15.12节中有所讨论。

当您知道所有参数的确切类型时,“简单”的选择方法是使用Class.getDeclaredMethod(String name, Class[] parameterTypes)。也许您需要检查方法的可访问性和类的超类/超接口。

但是,这并不包括以下任何一种情况,因此它有点无用:

  • 装箱/拆箱基本类型
  • 子类型
  • 可变参数
  • 空参数(除非解释器知道类型; 在编译时,任何不确定性都将通过将null强制转换为类/接口来消除)
  • 基本类型转换(不是Java的一部分,但在语言上下文中允许 - 例如Rhino Javascript,其中所有数字都是浮点数,因此Java代码可能会采用int,但调用者传递一个数字,该数字可以是intdouble

(下面是前三个示例的快速示例)

是否有任何知名框架库可帮助解决此问题?

package com.example.test.reflect;

import java.lang.reflect.Method;

public class MethodResolutionTest {
    public void compute(int i)              { /* implementation... */ }
    public void compute(Long l)             { /* implementation... */ }
    public void compute(Object obj)         { /* implementation... */ }
    public void compute(String... strings)  { /* implementation... */ }

    public static void main(String[] args) {
        Class<?> cl = MethodResolutionTest.class;

        /* these succeed */
        findAndPrintMethod(cl, "compute", int.class);
        findAndPrintMethod(cl, "compute", Long.class);
        findAndPrintMethod(cl, "compute", Object.class);
        findAndPrintMethod(cl, "compute", String[].class);

        /* these fail */
        findAndPrintMethod(cl, "compute", Integer.class);
        findAndPrintMethod(cl, "compute", long.class);
        findAndPrintMethod(cl, "compute", MethodResolutionTest.class);
        findAndPrintMethod(cl, "compute", String.class, String.class);
    }
    private static void findAndPrintMethod(Class<?> objectClass, 
            String methodName, Class<?>... parameterTypes) 
    {
        try {
            Method method = findMethod(objectClass, methodName, 
                   parameterTypes);
            System.out.println(method.toString());
        }
        catch (SecurityException e) {
            e.printStackTrace();
        }
        catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
    private static Method findMethod(Class<?> objectClass, 
            String methodName, Class<?>[] parameterTypes) 
        throws SecurityException, NoSuchMethodException 
    {
        return objectClass.getDeclaredMethod(methodName, parameterTypes);
    }
}

1
@Jonathon:我知道isAssignableFrom。我已经用子类型和装箱/拆箱实现了一些自己的东西。然后我开始使用可变参数,结果变得很麻烦,我想:“等一下,我为什么要这样做呢?”所以我特别寻找一个现成的库。(或者至少是一组好的现成测试用例)否则我可以自己完成,但这很麻烦。 - Jason S
1
除非你找到一个好用的库,否则我认为无论你做什么都会很丑陋难以阅读。 - Jonathon Faust
是的,我知道。那么如何吸引Google、Oracle、IBM、Apache或其他公司的Java半神来制作一个良好的非病毒开源库来完成这个任务呢?在我看来,这是Java反射中缺失的一块。我可以为自己的目的想出一些可行的方案,但我认为它远非完美,无论是正确性/文档/可维护性。 - Jason S
4个回答

3

啊!看起来很有前途,但是它只解决了泛型类型,对于方法解析没有任何作用。但至少这是一个开始,我敢打赌我可以说服作者扩展它。 - Jason S

2

Commons BeanUtils提供了查找匹配方法的功能:

getMatchingAccessibleMethod

它可以处理原始类型,但是根据文档所说,这种方式有些不确定性。


1
请注意,在getMatchingAccessibleMethod中,原始匹配是单向的-参数Long.class将匹配foo(long)Long.TYPE将不匹配foo(Long) - McDowell
+1:@Bengt:太好了,发现Apache有一些工具,也许不是我想要的,但至少有点东西。 - Jason S

0

guava-discuss 上的一位用户建议我看看 Mirror library

不幸的是,它目前也不能处理重载分辨。


-1

我在使用MVEL和属性方面取得了一些成功,但我不记得它是否可以调度方法调用。

然而,您可能正在寻找完全不同的语言。考虑到问题的性质,我建议看一下Groovy,它与Java集成非常干净。


嗯,由于各种原因,我“卡”在Java上了,最大的原因是可维护性(添加不同的语言会极大地限制我从其他开发人员那里获得帮助的能力)。 - Jason S

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接