【问题标题】:Java Reflection: Code runs fine in Debugger but not in "normal" running modeJava 反射:代码在调试器中运行良好,但不是在“正常”运行模式下
【发布时间】:2016-10-05 12:58:09
【问题描述】:

我正在尝试从方法数组中调用静态方法。这在调试器中工作得很好,但在正常运行模式下却不行。这是为什么呢?

下面的代码cmets中有更多描述..

编辑为了更容易复制只需在调试器与正常模式下运行这个类:

public class Stackoverflowquestion {

public static class Backautomat {
    private String aktuellBackendeBrotsorte = "Butterbrot";
    //Test für Statische Methoden: Brauche ich dazu auch eine Instanz für Invoke? 
    public static String getBezeichnung(){
        return "Bezeichnung: Bester-Backautomat-Ever";
    }
    //Test für Methoden ohne Parameterliste
    public boolean backautomat_starten(){
        return true;
    }
}

public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    //Get all methods of class
    Method[] backaudomadMethoden = Backautomat.class.getMethods();
    //Get first Method of class -> I know this one is static -> see in source "Backautomat"
    Method backMethod =  backaudomadMethoden[0];
    //Printing out Method Name: In Debugger this returns the static method name: getBezeichnung(),
    //In "normal" running mode (Run -> Run as -> Java Application) it prints out the second method: backautomat_starten()
    System.out.println(backMethod.getName());
    //Invocation is successfull in debugger
    //Invocation throws exception running in "normal" mode
    System.out.println(String.valueOf(backMethod.invoke(null)));

}

EDIT 异常如下所示:

backautomat_starten Exception in thread "main" java.lang.NullPointerException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.relfection.easy.example.Stackoverflowquestion.main(Stackoverflowquestion.java:31)

【问题讨论】:

  • 还有什么例外?您能否提供minimal reproducible example,以便我们自己复制它,而无需将不同的位复制并粘贴到不同的文件中? (我们应该能够创建一个新文件,复制、粘贴、编译、运行并查看错误。)
  • Class.getMethods() 不提供任何保证顺序的方法。所以在调试器中运行可以对顺序产生影响。事实上,anything 可以对该顺序产生影响,但调试器的情况甚至是合理的……
  • 来自getMethods() 的文档:“返回数组中的元素没有排序,也没有任何特定的顺序。”
  • 如果你想得到正确的方法,只需使用Backautomat.class.getMethod("getBezeichnung")...

标签: java methods reflection nullpointerexception static


【解决方案1】:

考虑documentation of Class.getMethods()

返回数组中的元素没有排序,也没有任何特定的顺序。

这意味着当前 JRE 的任意方面都可能产生改变结果的副作用,包括在调试器中运行。

因此,如果数组中的第一个方法不是您所期望的,那么在尝试像static 方法一样运行实例方法时获得与预期不同的名称并产生异常,是相同错误假设的症状。

【讨论】:

  • 感谢您的回答,这解释了问题。我只是好奇,因为它总是在调试器中工作,但不是在正常模式下。
  • 跟踪产生差异的实际代码路径可能需要深入了解实际实现。为了理解这个问题,了解必须加载启用 JVM 和调试器之间通信的某些代码就足够了,这也可能会影响某些事物的初始化顺序,这可能会对这些微妙的事物产生影响就像getMethods() 返回的元素顺序一样。由于无法预测此信息是否缓存以及缓存多长时间,因此同一会话中后续调用的顺序甚至可能会发生变化……
  • 好吧,这太过分了。感谢您的详细解答!
【解决方案2】:

https://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Method.html#invoke(java.lang.Object,%20java.lang.Object...)

这表明您在传入的已定义对象上调用该方法

String.valueOf(backMethod.invoke(null));

这里你传入 null 作为对象,所以你试图调用一个 null 对象的方法。

类似于做类似的事情

Object x = null;
x.toString();

显然 x.toString() 会抛出 NPE

【讨论】:

  • 此外,文档清楚地说明了为什么这适用于静态方法:如果底层方法是静态的,则忽略指定的 obj 参数。它可能为空。
  • 啊是的,所以它只是返回的方法的顺序,所以很明显,当它们在调试时,它是一个顺序,正常运行是另一个
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多