一篇关于静态初始化块、静态成员、初始化块、构造函数执行顺序和用法的文章
最编程
2024-03-31 10:25:28
...
Tips
- 非静态初始化块基本和构造函数一个作用,可以避免构造函数的代码重复。初始化块在类的每次构造都会执行
- 静态初始化块只在类加载执行一次
一个有意思的盲区:
执行psvm的时候,类的构造函数并不会执行,也就是说这时候类的实例并不存在。
public static void main(String[] args) {}
测试执行顺序
C extens B,B extends A , Main类中 new C()
public class InitLearn {
static class A{
static Print pA1 =new Print("static pA1");
static {
System.out.println("Static Initialization Block A");
}
static Print pA2 =new Print("static pA2");
{
System.out.println("Initialization Block A Before Construct");
}
public A(){
System.out.println("Construct A");
}
{
System.out.println("Initialization Block A After Construct");
}
};
static class B extends A{
static Print pB1 =new Print("static pB1");
static Print pB2 =new Print("static pB2");
static {
System.out.println("Static Initialization Block B");
}
{
System.out.println("Initialization Block B Before Construct");
}
public B(){
System.out.println("Construct B");
}
{
System.out.println("Initialization Block B After Construct");
}
};
static class C extends B{
static Print pC1 =new Print("static pC1");
static {
System.out.println("Static Initialization Block C");
}
static Print pC2 =new Print("static pC2");
{
System.out.println("Initialization Block C Before Construct");
}
public C(){
System.out.println("Construct C");
}
{
System.out.println("Initialization Block C After Construct");
}
};
static class Print{
public Print(String v){
System.out.println(v);
}
}
static {
System.out.println("static{} of the class run psvm to test");
}
public static void main(String[] args) {
new C();
//new C();
}
}
输出:
static{} of the class run psvm to test //测试类的静态初始化块,在调用psvm前
static pA1 //A类静态成员 定义在静态初始化块前
Static Initialization Block A //A类静态初始化块
static pA2 //A类静态成员 定义在静态初始化块后
static pB1 //B类静态成员 定义在静态初始化块前
static pB2 //B类静态成员 定义在静态初始化块前
Static Initialization Block B //B类静态初始化块
static pC1 //C类静态成员 定义在静态初始化块前
Static Initialization Block C //C类静态初始化块
static pC2 //C类静态成员 定义在静态初始化块后
Initialization Block A Before Construct //A类初始化块
Initialization Block A After Construct //A类初始化块
Construct A //A类构造方法
Initialization Block B Before Construct
Initialization Block B After Construct
Construct B
Initialization Block C Before Construct
Initialization Block C After Construct
Construct C
有趣的现象
-
InitLearn类是肯定没有被实例化过的,但是由于执行main入口函数用到了InitLearn类,于是static初始化块也被执行了;
-
所有的静态初始化块都优先执行,其次才是非静态的初始化块和构造函数,它们的执行顺序是:
- 父类的静态初始化块/静态成员,顺序是声明顺序
- 子类的静态初始化块/静态成员,顺序是声明顺序
- 父类的初始化块(无论定义在构造方法前还是后)
- 父类的构造函数
- 子类的初始化块(无论定义在构造方法前还是后)
- 子类的构造函数
-
如果之后再new 一个B(),只会出现以下日志,静态的初始化过程只执行一次
Initialization Block A Before Construct Initialization Block A After Construct Construct A Initialization Block B Before Construct Initialization Block B After Construct Construct B Initialization Block C Before Construct Initialization Block C After Construct Construct C
总结
- 静态初始化块的优先级最高,也就是最先执行,并且仅在类第一次被加载时执行;
- 非静态初始化块和构造函数后执行,并且在每次生成对象时执行一次;
- 非静态初始化块的代码会在类构造函数之前执行。因此若要使用,应当养成把初始化块写在构造函数之前的习惯,便于调试;
- 静态初始化块既可以用于初始化静态成员变量,也可以执行初始化代码;
- 非静态初始化块可以针对多个重载构造函数进行代码复用。
参考
www.cnblogs.com/BlackStorm/…
上一篇: 最完整的 Resharper 快捷键汇总
下一篇: 创意调试技巧