Java:当方法明显存在时出现NoSuchMethodException

51

在我的当前项目中,我感觉有必要使用反射来创建一种模拟回调系统。然而,我在让反射实际起作用方面遇到了问题。以下是有问题的代码:

public Callback(Object parentObj, String methodName, Class<?>...parameters)
{
    if(parentObj == null)
        throw new IllegalArgumentException("parentObj cannot be null", new NullPointerException());

    Class<?> clazz = parentObj.getClass();

    // Trace debugging, see output
    for(Method m : clazz.getDeclaredMethods())
        if(m.getName().equals("myMethod")) System.out.println (m);

    try { this.method = clazz.getMethod(methodName, parameters); }
    catch(NoSuchMethodException nsme) { nsme.printStackTrace(); } // Exception caught
    catch(SecurityException se) { se.printStackTrace(); }

    this.parentObj = parentObj;
    this.parameters = parameters;
}

我构建Callback对象时,使用的语法类似于:

new Callback(this, "myMethod", boolean.class)

当我尝试创建我的伪回调时,它会触发NoSuchMethodException异常处理块。我已经在上面包含了一些跟踪调试信息来显示我的一个方法失败的输出。输出:

private void my.package.MyClass.myMethod(boolean)
java.lang.NoSuchMethodException: my.package.MyClass.myMethod(boolean)
    at java.lang.Class.getMethod(Class.java:1605)
    at my.package.other.Callback.<init>(Callback.java:63)

我无法找出问题,于是开始查找,但结果很少。最好的结果是关于已编译JAR和运行时之间版本冲突的提及。然而,MyJar.jar/META-INF/MANIFEST.MF 包含 Created-By: 1.6.0_02 (Sun Microsystems Inc.)。我的IDE正在运行 C:\Program Files\Java\jdk1.6.0_02\bin\javac.exe 编译我的项目,我使用 C:\Program Files\Java\jdk1.6.0_02\bin\java.exe 运行我的JAR。

我不知道为什么 Class.getMethod 声称该方法不存在,但是 Class.getMethods 看起来没有找到任何问题。有办法帮忙吗? :(


1
这就是为什么你不能依赖反射,因为它在最好的情况下也是不可靠的。 - quantumSoup
我不会说它不可靠,但它可能会很复杂和低效。 - Adam Crume
1
它肯定比编译器可以证明正确的东西不可靠。 :-) - Laurence Gonsalves
4个回答

124

你的方法是私有的,但是getMethod()只返回公共方法。

你需要使用getDeclaredMethod()


是的!这解决了问题,而不用强制我使用公共方法。谢谢! - Brian S
3
3年后...这在我的情况下很有道理。虽然我开始阅读http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Class.html#getMethod(java.lang.String, java.lang.Class...)中两种方法的文档,但它们没有提到这样的信息。也许你查看了代码?干得好。+1 - Lzh
我连续撞墙了两个小时,真是头疼啊。谢谢你! - Saif Asif
1
Java的命名规范真是太棒了...那么getPrivateMethod怎么样...天哪 - Nick
1
这帮了我,但是反过来。我试图使用 getDeclaredMethod() 调用一个公共方法,但它找不到。改用 getMethod(),现在可以正常工作了。 - Russ Wheeler

8
你需要确保方法的参数列表完全正确,以便成功调用所需的方法。
我发现,在反射时采取小步骤非常重要,因为编译器并不会提供帮助。请编写一个小片段,确切地调用你在这个特定情况下想要调用的方法,当它可以工作时,将其推广到这里的框架中。我会关注传递的参数。

2
这是我的问题所在。我没有为我想要获取的方法提供参数类型。我的代码之前看起来像 Method method = SearchApiController.class.getMethod("searchPost"),但是我的方法需要一堆参数,而我在通过反射获取它时错过了指定它们。我的修改后的代码完美地工作了。Method method = SearchApiController.class.getMethod("searchPost", String.class, SearchQuery.class, String.class, String.class, String.class); - Shrikant Prabhu

5

getMethod 的 Javadoc 不是很明确,但看起来它可能会针对非公共方法抛出 NoSuchMethodException 异常,而您的方法是私有的。


2
没错,就是这样。你的建议让我仔细研究了Class中的源代码。getMethod 调用 (私有的) getMethod0getMethod0 又调用了 privateGetDeclaredMethods(true),其中 true 表示“只获取公共方法”。 - Brian S

0

可能导致NoSuchMethodException的版本问题并不是编译器版本之间的差异。而是在编译时与运行时(在您的情况下)MyClass的版本差异。

由于您正在使用反射,所以您遇到的问题可能与版本无关。当然,这不能解释getMethodgetDeclaredMethods之间的不同行为,因为它们都针对同一个类实例运行,因此版本差异实际上是不可能的。

您确定参数与实际方法匹配吗?


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