定义包含 main() 方法的相同 class 的实例变量时出现 StackOverflowError

Getting StackOverflowError when define instance variable of same class containing main() method

我试图在 google 上搜索答案,但没有找到。为什么下面的程序给出 WhosebugError.

public class HelloWorld {
    private HelloWorld obj = new HelloWorld();  // (HelloWorld.java:2)

    public static void main(String args[]) {
        HelloWorld obj = new HelloWorld();
        obj.printHello();
    }

    private void printHello(){
        System.out.println("Hello world");
    }
}

输出:

Exception in thread "main" java.lang.WhosebugError
    at HelloWorld.<init>(HelloWorld.java:2)
    at HelloWorld.<init>(HelloWorld.java:2)
    ....................

如果我注释实例变量obj,那么程序会打印“Hello world”并且没有错误。 见下文:

public class HelloWorld {
//    private HelloWorld obj = new HelloWorld();

    public static void main(String args[]) {
        HelloWorld obj = new HelloWorld();
        obj.printHello();
    }

    private void printHello(){
        System.out.println("Hello world");
    }
}

输出:

Hello world

循环实例化错误。难怪!

是的,它会抛出 WhosebugException 因为当你这样做时,

HelloWorld obj = new HelloWorld();

在你的 main 中,你的 class 将被初始化 并且它会到达第 2 行,从那里它会尝试再次初始化 HelloWorld 然后它到达第 2 行...循环继续。

这可能会发生即使您的对象不使用相同的名称也是如此。

public class HelloWorld {
    private HelloWorld obj = new HelloWorld();  // (HelloWorld.java:2)

    public static void main(String args[]) {
        HelloWorld obj = new HelloWorld();
        obj.printHello();
    }

    private void printHello(){
        System.out.println("Hello world");
    }
}

创建 class 的新实例时,就像您在 main 方法中所做的那样:

HelloWorld obj = new HelloWorld();

class 的实例变量的变量初始化器被执行,在 HelloWorld 的情况下,是这里的这一行:

private HelloWorld obj = new HelloWorld();  // (HelloWorld.java:2)

该行创建另一个 HelloWorld 实例,导致同一行再次 运行。要再次 运行 该行,需要创建另一个实例,这意味着同一行必须再次 运行 一次又一次,依此类推...

另一种思考方式是想象 HelloWorld 有一个这样的构造函数:

class HelloWorld {
    private HelloWorld obj;
    public HelloWorld() {
        obj = new HelloWorld();
    }
}

你应该清楚地看到无限递归的发生。

如果您查看编译器生成的字节码,您会发现您的代码编译后类似于以下代码。

public class HelloWorld {
    private HelloWorld obj;  // (HelloWorld.java:2)

    public HellowWorld(){
       obj = new HelloWorld(); // obj created in the constructor. Point-1
    }

    public static void main(String args[]) {
        HelloWorld obj = new HelloWorld();
        obj.printHello();
    }

    private void printHello(){
        System.out.println("Hello world");
    }
}

因此,如果您查看第 1 点,您会看到新的 HelloWorld() 调用导致递归调用,没有任何终止条件,这将导致 Whosebug.For 您在下面的参考是字节代码:

public class abc.HelloWorld {
  public abc.HelloWorld();
    Code:
       0: aload_0
       1: invokespecial #10                 // Method java/lang/Object."<init>":()V
       4: aload_0
       5: new           #1                  // class abc/HelloWorld
       8: dup
       9: invokespecial #12                 // Method "<init>":()V
      12: putfield      #13                 // Field obj:Labc/HelloWorld;
      15: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #1                  // class abc/HelloWorld
       3: dup
       4: invokespecial #12                 // Method "<init>":()V
       7: astore_1
       8: aload_1
       9: invokespecial #20                 // Method printHello:()V
      12: return
}