【问题标题】:Java: NoSuchMethodException when method clearly existsJava:当方法明显存在时出现 NoSuchMethodException
【发布时间】:2012-09-12 08:21:25
【问题描述】:

在我当前的项目中,我觉得有必要使用反射在 Java 中创建一种模拟回调系统。但是,我在让我的反思真正发挥作用时遇到了问题。错误代码如下:

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 catch 块。我在上面包含了一些跟踪调试,以显示我的一种方法失败的输出。输出:

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 似乎没有问题找到它。帮助? :(

【问题讨论】:

  • 这就是为什么你不依赖反射,它充其量是不可靠的。
  • 我不会说它不可靠,但它可能很复杂且效率低。
  • 它肯定不如你的编译器可以证明是正确的可靠。 :-)

标签: java reflection


【解决方案1】:

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

您需要使用getDeclaredMethod()

【讨论】:

  • 是的!这解决了问题,而不会强迫我使用公共方法。谢谢!
  • 3 年后......这对我来说很有意义。虽然我开始在docs.oracle.com/javase/1.5.0/docs/api/java/lang/…、java.lang.Class...) 阅读这两种方法的文档,但他们没有提到这些信息。也许您查看了代码?对你有益。 +1
  • 连续 2 个小时把我的头撞在墙上。谢谢大佬!
  • 真棒命名约定 java... getPrivateMethod 怎么样 .. lordy
  • 这对我有帮助,但反过来。我有一个我试图用 getDeclaredMethod() 调用的公共方法,但它没有找到它。切换到 getMethod() 就可以了
【解决方案2】:

您需要参数列表对于您希望调用成功的方法绝对正确。

我发现在进行反射时,微小的步骤很重要,因为编译器没有帮助。编写一个小的 sn-p,它实际上在 this 特定情况下准确调用您想要的方法,然后当它起作用时,将其推广到此处的框架中。我会专注于传递的参数。

【讨论】:

  • 这是我的问题。我没有为我想要获得的方法提供参数类型。我之前的代码看起来像Method method = SearchApiController.class.getMethod("searchPost"),但我的方法是采用一堆我在通过反射获取时错过指定的参数。我的代码工作后就像一个魅力。 Method method = SearchApiController.class.getMethod("searchPost", String.class, SearchQuery.class, String.class, String.class, String.class);
【解决方案3】:

getMethod 的 Javadoc 不是显式的,但看起来它可能会为非公共方法抛出 NoSuchMethodException,而您的方法是私有的。

【讨论】:

  • 是的,就是这样。您的建议让我倾注了 Class 的源代码。 getMethod 呼叫(私人)getMethod0getMethod0 调用privateGetDeclaredMethods(true),其中true 是“publicOnly
【解决方案4】:

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

不过,由于您使用的是反射,因此您发出的问题可能与版本控制无关。当然,这并不能解释 getMethodgetDeclaredMethods 之间的不同行为,因为您是针对同一个 Class 实例运行它们,因此实际上不可能存在版本差异。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-30
    相关资源
    最近更新 更多