【问题标题】:Java method invocation orderJava方法调用顺序
【发布时间】:2013-10-28 11:10:17
【问题描述】:
public class MyClassTest {

    private static MyClass m;

    public static void main(String[] args) {
        m.initMe(getint());
    }

    public static int getint() {
        m = new MyClass();
        return (int) Math.random()*100;
    }

}

class MyClass{

    int i;

    void initMe(int i) {
       this.i = i;
       System.out.println(this.i);
     }

}

这段代码sn-p给出NullPointerException,导致initMe()getint被调用之前被调用。这个问题的根本原因是什么?是 JAVA 按值传递,所以引用更新不受影响。

给我背后的正当理由。

【问题讨论】:

  • main是第一个调用的方法,初始化m,然后调用MyClass的initMe。
  • @Batty 是的,如果我首先调用getint,那么代码运行完美......但我问的是什么原因,所以我的代码给了我例外。

标签: java nullpointerexception


【解决方案1】:

编译器可以生成您的想法

  • 执行每个参数的代码
  • 将结果入栈
  • 调用方法(m 将被初始化)

但是Java specifications 描述了在评估参数之前必须执行的几个步骤。在知道如何处理参数之前,JVM 必须能够识别对象的类型(运行时类型)。

这是生成的字节码

public static void main(java.lang.String[]);
  Code:
     0: getstatic     #2                  // Field m:LMyClass;
     3: invokestatic  #3                  // Method getint:()I
     6: invokevirtual #4                  // Method MyClass.initMe:(I)V
     9: return        

如您所见,第一步是将m 加载到堆栈上。它将加载空值。然后调用getint,它将设置m,但invokevirtual使用的值将是JVM堆栈上已经加载的值。

【讨论】:

    【解决方案2】:

    中所述

    JLS section 15.12. Method Invocation Expressions

    方法调用表达式用于调用类或实例 方法。

    MethodInvocation:
        MethodName ( ArgumentListopt )
        Primary . NonWildTypeArgumentsopt Identifier ( ArgumentListopt )
        super . NonWildTypeArgumentsopt Identifier ( ArgumentListopt )
        ClassName . super . NonWildTypeArgumentsopt Identifier ( ArgumentListopt )
        TypeName . NonWildTypeArguments Identifier ( ArgumentListopt )
    
    The definition of ArgumentList from §15.9 is repeated here for convenience:
    
    
    ArgumentList:
        Expression
        ArgumentList , Expression
    

    在编译时解析方法名比 由于方法的可能性而解析字段名称 超载。在运行时调用方法也更复杂 由于实例方法的可能性,而不是访问字段 覆盖。

    确定方法调用将调用的方法 表达涉及几个步骤。以下三个部分 描述方法调用的编译时处理;这 方法调用表达式类型的确定是 §15.12.3 中描述。

    现在您看到要调用哪个方法涉及类型识别。由于 java 支持方法覆盖,因此您可以使用不同的类型实现相同的方法。因此,在解决方法参数 instance 之前,确定类型在您的情况下结果为 null 并导致 NPE。

    希望对你有帮助。

    【讨论】:

      【解决方案3】:

      main 是调用 MyClass 的 initMe 之前调用的第一个方法,初始化 m。喜欢

      private static MyClass m = new MyClass();
      

      看,m.initMe(getint()); 在 m 上调用 initMe(),但你还没有初始化 m,因为这是 main 方法的第一行,所以 m = null,因此异常。

      【讨论】:

        【解决方案4】:

        没有实例化MyClass,你已经调用了它的方法initMe。 所以,由于对象没有被实例化,你会得到这个异常 将其更改为:

         private static MyClass m = new MyClass();
        

        【讨论】:

          【解决方案5】:

          m.initMe(getint());

          m.initMe() 被调用时,m 仍然未初始化。它仅在 getint() 中初始化。因此,您需要先初始化您的m,然后才能使用它调用使用它的方法。

          private static MyClass m = new MyClass(); // Declared and initialized
          public static void main(String[] args) {
            m.initMe(getint()); // Thus, its safe here to call a method now
          }
          public static int getint() {
            return (int) Math.random()*100;
          }
          

          或者你可以在调用initMe()之前初始化它,也可以在main()方法中。

          private static MyClass m; // Declared here
          public static void main(String[] args) {
            m = new MyClass(); // initialized here
            m.initMe(getint()); // Thus, its safe here to call a method now
          }
          public static int getint() {
            return (int) Math.random()*100;
          }
          

          【讨论】:

            【解决方案6】:

            首先你必须初始化'm'

            private static MyClass m = new MyClass();
            

            Java 确实通过引用来操作对象,并且所有对象变量都是引用。 Java 不通过引用传递方法参数,而是通过值传递。

            【讨论】:

              【解决方案7】:

              您正在 getint() 方法中创建 MyClass object

              public static int getint() {
                  m = new MyClass();
                  return (int) Math.random()*100;
                }
              

              您需要在main(String[] args) 方法中创建MyClass object

              public static void main(String[] args) {
                 m = new MyClass();
                 m.initMe(getint());
              }
              

              【讨论】:

                猜你喜欢
                • 2016-01-02
                • 2014-07-27
                • 1970-01-01
                • 1970-01-01
                • 2015-09-02
                • 1970-01-01
                • 2014-03-21
                • 2013-11-07
                • 2012-03-15
                相关资源
                最近更新 更多