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是否按值传递,因此参考更新不受影响。
给我背后的正当理由。
答案 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());
}