在 Java 中使用静态关键字创建对象

2022-09-04 03:22:52
class abc {
    int a = 0;
    static int b;
    static abc h = new abc(); //line 4

    public abc() {
        System.out.println("cons");
    }

    {
        System.out.println("ini");
    }

    static {
        System.out.println("stat");
    }
}

public class ques {
    public static void main(String[] args) {
        System.out.println(new abc().a);
    }
}

当我编写此代码时,我按如下顺序获得输出:

ini
cons
stat
ini
cons
0

在这里,当我在中创建新对象时,got加载了变量和块,并按写入顺序执行变量和块。当控制来到第 4 行时,将调用实例初始化块。为什么?为什么在第4行创建新对象时不调用静态块,并且直到那时静态块甚至没有被调用一次,所以按照惯例应该调用静态块。为什么会出现这种意外的输出?main(), class abcstaticstatic abc h = new abc();


答案 1

JLS

静态初始值设定项和类变量初始值设定项按文本顺序执行,并且不能引用在使用后声明其声明以文本方式显示的类中声明的类变量,即使这些类变量在作用域内 (§8.3.2.3)。此限制旨在检测在编译时大多数循环初始化或其他格式错误的初始化。

这正是您的情况。

下面是您的原始示例:http://ideone.com/pIevbX - 在分配静态实例之后的 go 的静态初始值设定项 - 因此静态初始值设定项无法执行 - 它是在静态变量初始化后的文本abcabc

让我们在静态初始化块之后移动第 4 行 - http://ideone.com/Em7nC1

class abc{
int a = 0;
static int b;
public abc() {
    System.out.println("cons");
}
{
    System.out.println("ini");
}
static {
    System.out.println("stat");
}
static abc h = new abc();//former line 4

}

现在您可以看到以下输出:

stat
ini
cons
ini
cons
0

现在初始化顺序更像你期望的 - 首先调用静态初始值设定项,然后以通用方式初始化的静态实例。abc


答案 2

静态字段初始化和静态块按声明的顺序执行。在你的例子中,代码在分离声明和初始化后等效于这个:

class abc{
    int a;
    static int b;
    static abc h;//line 4

    static {
        h = new abc();//line 4 (split)
        System.out.println("stat");
    }

    public abc() {
        a = 0;
        System.out.println("ini");
        System.out.println("cons");
    }
}

public class ques{
    public static void main(String[] args) {
        System.out.println(new abc().a);
    }
}

因此,当您从代码中到达第 4 行时,静态初始化实际上正在执行中,但尚未完成。因此,在可以打印之前调用构造函数。stat