Java方法调用顺序

时间:2013-10-28 11:10:18

标签: java nullpointerexception

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);
     }

}

此代码段提供NullPointerException,导致initMe()在调用getint之前被调用。这个问题的根本原因是什么? JAVA是否按值传递,因此参考更新不受影响。

给我背后的正当理由。

7 个答案:

答案 0 :(得分:2)

编译器可以生成您的想法

  • 执行每个参数的代码
  • 将结果放在堆栈上
  • 调用方法(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。它将加载null。然后调用getint,它将设置m,但invokevirtual使用的值将是已经加载到JVM堆栈上的值。

答案 1 :(得分:1)

中所述
  

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支持方法覆盖,因此您可以使用不同的类型实现相同的方法。因此,在解析方法之前,会识别实例类型,在您的情况下,该类型变为空并导致NPE。

希望它有所帮助。

答案 2 :(得分:0)

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

private static MyClass m = new MyClass();

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

答案 3 :(得分:0)

如果没有实例化MyClass,则调用其方法initMe。 因此,由于对象未实例化,因此您将获得此异常 将其更改为:

 private static MyClass m = new MyClass();

答案 4 :(得分:0)

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;
}

答案 5 :(得分:0)

首先你需要初始化'm'

private static MyClass m = new MyClass();

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

答案 6 :(得分:0)

您正在MyClass方法

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

您需要在MyClass object方法

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