Java中的类初始化顺序(class initialization order)定义了字段、块和构造函数的初始化顺序。简而言之:
class Parent { static { System.out.println("Parent static"); } { System.out.println("Parent init"); } Parent() { System.out.println("Parent constructor"); } } class Child extends Parent { static { System.out.println("Child static"); } { System.out.println("Child init"); } Child() { System.out.println("Child constructor"); } } // new Child() -> 顺序是什么?
输出将是:
首先是父类的静态块,然后是子类的静态块,然后是非静态块和构造函数按继承顺序执行。
问题: 类中的静态初始化器将在何时执行:
class Ex {
static { System.out.println("static"); }
}
— 在创建第一个实例时,还是在第一次访问任何静态方法/字段时?
答案: 静态初始化器在首次访问类时执行,包括对任何静态成员(方法/字段)的访问,而不仅仅是在创建实例时。
故事
在银行应用程序中,静态连接池在静态块中初始化,但由于在创建第一个实例之前访问静态方法,连接尚未创建。这导致在负载下运行时出现NullPointerException。
故事
日志服务依赖于在父类构造函数调用之后初始化的非静态字段。日志被记录到null记录器中,导致重要的错误消息丢失。
故事
在添加新字段并赋予初始值时,开发人员将其放在初始化块之后:块试图使用尚未初始化的字段,导致应用程序启动时出现错误,且原因难以追踪。