Java中运行静态/实例初始化程序块的顺序是什么?
假设一个项目包含几个类,每个类都有一个静态初始化块。 这些区块以什么顺序运行? 我知道在一个类中,这些块按它们在代码中出现的顺序运行。 我已经读过,在不同的类中它是一样的,但我写的一些示例代码不同意这一点。 我用这个代码:
package pkg;
public class LoadTest {
public static void main(String[] args) {
System.out.println("START");
new Child();
System.out.println("END");
}
}
class Parent extends Grandparent {
// Instance init block
{
System.out.println("instance - parent");
}
// Constructor
public Parent() {
System.out.println("constructor - parent");
}
// Static init block
static {
System.out.println("static - parent");
}
}
class Grandparent {
// Static init block
static {
System.out.println("static - grandparent");
}
// Instance init block
{
System.out.println("instance - grandparent");
}
// Constructor
public Grandparent() {
System.out.println("constructor - grandparent");
}
}
class Child extends Parent {
// Constructor
public Child() {
System.out.println("constructor - child");
}
// Static init block
static {
System.out.println("static - child");
}
// Instance init block
{
System.out.println("instance - child");
}
}
并得到这个输出:
开始
静态 - 祖父母
静态 - 父母
静态 - 孩子
实例 - 祖父母
构造函数 - 祖父母
实例 - 父
构造函数 - 父类
实例 - 孩子
构造函数 - 孩子
结束
从这个问题的明显答案是,父母的块在他们的孩子之前运行,但这可能只是一个巧合,并且如果两个班不在同一个层次结构中则无济于事。
编辑:
我通过将其附加到LoadTest.java来修改示例代码:
class IAmAClassThatIsNeverUsed {
// Constructor
public IAmAClassThatIsNeverUsed() {
System.out.println("constructor - IAACTINU");
}
// Instance init block
{
System.out.println("instance - IAACTINU");
}
// Static init block
static {
System.out.println("static - IAACTINU");
}
}
正如班级名称所暗示的,我从来没有在任何地方引用新班级。 新方案产生的结果与旧方案相同。
首次访问类时,类的静态初始化器会运行,既可以创建实例,也可以访问静态方法或字段。
所以,对于多个类,这完全依赖于运行这些类的代码来加载。
请参阅JLS第8版的第12.4和12.5节,他们详细介绍了所有这些(静态为12.4,实例变量为12.5)。
对于静态初始化(12.4节):
类或接口类型T将在第一次出现以下任何一项之前立即被初始化:
(和几个黄鼠狼字条款)
基思和克里斯的答案都很好,我只是为我的具体问题添加更多细节。
静态初始化块按其类的初始化顺序运行。 那么,这是什么顺序呢? 根据JLS 12.4.1:
类或接口类型T将在第一次出现以下任何一项之前立即被初始化:
在类Class和包java.lang.reflect中调用某些反射方法也会导致类或接口初始化。 在任何其他情况下,类或接口都不会被初始化。
为了说明,下面是对示例中发生的事件的演练:
上一篇: In what order do static/instance initializer blocks in Java run?