Java方法调用顺序

Java方法调用顺序,java,nullpointerexception,Java,Nullpointerexception,此代码段给出了NullPointerException,导致在调用getint之前调用initMe()。这个问题的根本原因是什么?是JAVA传递值,因此引用更新不受影响 请给出正确的原因。main是调用MyClass的initMe之前调用的第一个方法initializem。像 public class MyClassTest { private static MyClass m; public static void main(String[] args) {

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


请给出正确的原因。

main是调用MyClass的initMe之前调用的第一个方法initializem。像

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

}

请参见,
m.initMe(getint())
在m上调用initMe(),但您尚未初始化m,因为这是main方法的第一行,因此
m=null
,因此出现异常。

在未实例化
MyClass
的情况下,您已调用其方法
initMe
。 因此,由于对象未实例化,因此您将获得此异常 将此更改为:

private static MyClass m = new MyClass();
m.initMe(getint())

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

 private static MyClass m = new MyClass();
或者,您可以在调用
initMe()
之前以及在
main()
方法中初始化它

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

首先,您必须初始化“m”

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

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

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

private static MyClass m = new MyClass();
您需要在
main(String[]args)
方法中创建
MyClass对象

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

编译器可以生成您想要的内容

  • 执行每个参数的代码
  • 将结果放在堆栈上
  • 调用方法(
    m
    将被初始化)
但是,本文描述了在评估参数之前必须执行的几个步骤。JVM必须能够识别对象的类型(运行时类型),然后才能知道如何处理参数

这是生成的字节码

public static void main(String[] args) {
   m = new MyClass();
   m.initMe(getint());
}
如您所见,第一步是在堆栈上加载
m
。它将加载null。然后调用
getint
,它将设置
m
,但
invokevirtual
使用的值将是已经加载到JVM堆栈上的值。

如中所述

JLS第15.12节。方法调用表达式

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

在编译时解析方法名比 解析字段名,因为可能存在方法错误 超载。在运行时调用方法也更复杂 而不是访问字段,因为可能使用实例方法 压倒一切的

确定将由方法调用调用的方法 表达包括几个步骤。以下三节 描述方法调用的编译时处理;这个 方法调用表达式类型的确定是 如§15.12.3所述

现在,您将看到identiry要调用的方法涉及类型标识。由于java支持方法重写,因此可以使用不同的类型实现相同的方法。因此,在解析方法参数之前,实例类型被标识,在您的例子中,该类型被证明为null并导致NPE


希望有帮助。

main是调用MyClass的initMe之前调用的第一个方法initialize m。@Batty是的,如果我先调用
getint
,然后代码运行正常,你是对的。。。但我在问原因是什么,所以我的代码给了我一个例外。
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        
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