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