初始化块
- 实际上,初始化块是一个假象,使用javac命令编译java类后,初始化块会消失,初始化代码被还原到每个构造器中代码的最前面
- 在实例化的过程中:前面的初始化块先执行,后面的后执行
- 初始化块的修饰符只能是 static
- 普通初始化块负责对对象执行初始化,静态初始化块负责对类执行初始化
- 初始化块只在创建java对象时隐式的执行,在构造器之前执行
当创建java对象时,初始化顺序是:
1、第一次类加载时:
-
先执行顶层父类的静态初始化代码,再向下追溯执行间接父类静态初始化代码,
最后执行直接父类静态初始化代码; -
静态初始化块和声明静态成员变量时指定的初始值都是给类的静态初始化代码,
它们的执行顺序与源码中书写顺序相同。
2、接着开始对对象实例化
- 先执行初始化块或声明实例变量时指定的初始值(两者执行顺序与源码书写顺序相同),
- 再执行构造器里的代码。
例子:
1 1 class Root{ 2 2 static { 3 3 System.out.println("Root的静态初始化块"); 4 4 } 5 5 6 6 { 7 7 System.out.println("Root的普通初始化块"); 8 8 } 9 9 1010 public Root() { 1111 System.out.println("Root的无参构造器"); 1212 } 1313 1414 } 1515 1616 class Mid extends Root{ 1717 static { 1818 System.out.println("Mid的静态初始化块"); 1919 } 2020 2121 { 2222 System.out.println("Mid的普通初始化块"); 2323 } 2424 2525 public Mid() { 2626 System.out.println("Mid的无参构造器"); 2727 } 2828 2929 public Mid(String msg) { 3030 this(); 3131 System.out.println("Mid的带参构造器,其参数值:" + msg); 3232 } 3333 3434 } 3535 3636 class Leaf extends Mid{ 3737 static { 3838 System.out.println("Leaf的静态初始化块"); 3939 } 4040 4141 { 4242 System.out.println("Leaf的普通初始化块"); 4343 } 4444 4545 public Leaf() { 4646 super("疯狂java"); 4747 System.out.println("Leaf的无参构造器"); 4848 } 4949 } 5050 5151 public class Test { 5252 public static void main(String[] args){ 5353 new Leaf(); 5454 new Leaf(); 5555 } 5656 }
执行结果:
Root的静态初始化块
Mid的静态初始化块
Leaf的静态初始化块
Root的普通初始化块
Root的无参构造器
Mid的普通初始化块
Mid的无参构造器
Mid的带参构造器,其参数值:疯狂java
Leaf的普通初始化块
Leaf的无参构造器
Root的普通初始化块
Root的无参构造器
Mid的普通初始化块
Mid的无参构造器
Mid的带参构造器,其参数值:疯狂java
Leaf的普通初始化块
Leaf的无参构造器
程序执行流程:
Root的静态初始化块 -->
Mid的静态初始化块 -->
Leaf的静态初始化块 -->
回到Test类new Leaf() -->
进入Leaf无参构造 -->
super进入Mid有参构造 -->
this进入MId无参构造 -->
super进入Root无参构造 -->
进入Root初始化块执行打印 -->
进入Super无参构造并执行打印 -->
进入Mid普通初始化块执行打印 -->
进入MId无参构造并执行打印 -->
进入Mid有参构造执行打印 -->
进入Leaf初始化块打印 -->
进入Leaf无参构造打印 --> .........