在类自己的静态初始值设定项中创建类的对象

2022-09-03 06:51:35

根据JLS

类或接口类型 T 将在首次出现以下任一项之前立即初始化

T 是一个类,并创建了 T 的一个实例。

它还说,

类的初始化包括执行其静态初始值设定项和类中声明的静态字段(类变量)的初始值设定项

由此推断出两点

  • 类初始化包括执行其静态初始值设定项
  • 如果实例化类,则会发生类初始化。

现在

我假设当我在一个类 Test 自己的(Test 自己的)静态初始值设定项中创建一个对象时,它应该向我抛出一个堆栈溢出,因为它应该重复调用自己,因为根据上述两点,类的实例化应该初始化类,并且初始化块具有类的实例化。当我在类自己的构造函数或自己的实例初始值设定项中实例化类时,会发生堆栈溢出。

例如

public class Test {

    static{
        System.out.println("static test");
        new Test();
    }
    {
       //new Test(); // This will give a stack overflow
        System.out.println("intializer");
    }

    public Test(){
        //new Test(); // This will give a stack overflow
        System.out.println("constructor");
    }
    public static void main(String[] args) {
    }

}

然而,结果是不同的。

结果:

静态测试初始化器构造函数

要么我对类的初始化感到困惑,要么如果我在这里错过了一些非常明显的东西,我会道歉,并感谢您的帮助。


答案 1

在 JLS 第 12.4.2 节中指定的类初始化过程的步骤 3 是

如果 C 的 Class 对象指示当前线程正在对 C 进行初始化,则这必须是初始化的递归请求。释放 LC 并正常完成。

在其静态初始值设定项中创建类的实例不会以递归方式重新初始化该类;检测到初始化的递归请求,并且不执行任何操作。

(请注意,“正常完成”意味着“操作已完成”,而不是“按照通常遵循的步骤完成操作”;它与“突然完成”相反,这意味着我们得到了某种异常或错误。


答案 2

静态初始值设定项仅在装入类时调用。在静态初始值设定项中实例化对象不会导致类再次加载,类的类加载只发生一次,类加载器在 JVM 实例的生命周期内缓存类。

如果在实例初始值设定项或构造函数中创建了新实例,则会收到堆栈溢出错误。


推荐