2
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 按值传递,所以引用更新不受影响。

给我背后的正当理由。

4

7 回答 7

2

编译器可以生成您的想法

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

但是Java 规范描述了在评估参数之前必须执行的几个步骤。在知道如何处理参数之前,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 堆栈上的值。

于 2013-10-28T11:24:08.483 回答
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 支持方法覆盖,因此您可以使用不同的类型实现相同的方法。因此,在解决方法参数之前,确定实例类型在您的情况下结果为 null 并导致 NPE。

希望能帮助到你。

于 2013-10-28T11:32:20.767 回答
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;
}
于 2013-10-28T11:13:30.373 回答
0

首先你必须初始化'm'

private static MyClass m = new MyClass();

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

于 2013-10-28T11:13:46.713 回答
0

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

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

您需要 MyClass objectmain(String[] args) 方法内创建

public static void main(String[] args) {
   m = new MyClass();
   m.initMe(getint());
}
于 2013-10-28T11:14:26.847 回答
0

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

private static MyClass m = new MyClass();

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

于 2013-10-28T11:11:34.697 回答
0

如果没有实例化MyClass,您就调用了它的方法initMe。因此,由于该对象未实例化,因此您将收到此异常 将其更改为:

 private static MyClass m = new MyClass();
于 2013-10-28T11:11:34.720 回答