1.单个类的初始化顺序
对于静态变量、静态初始化块、变量、初始化块、构造器,它们的初始化顺序依次是(静态变量、静态初始化块)>(变量、初始化块)>构造器。
图示:
通过下面的测试代码来验证这一点:
package com.ttbank.flep.file.test; public class TradeTest { // 静态变量 public static String staticField = "静态变量"; // 变量 public String field = "变量"; // 静态初始化块 static { System.out.println(staticField); //注意:静态初始化块中使用静态变量,所以静态变量要在静态代码块前 System.out.println("静态初始化块"); } // 初始化块 { System.out.println(field); System.out.println("初始化块"); } // 构造方法 public TradeTest() { System.out.println("构造方法"); } public static void main(String[] args) { new TradeTest(); new TradeTest(); } }
执行效果图:
静态代码块,在虚拟机加载类的时候就会加载执行,而且只执行一次;
非静态代码块,在创建对象的时候(即new一个对象的时候)执行,每次创建对象都会执行一次。
2.对于继承的情况初始化顺序
父类:
package com.ttbank.flep.file.test; public class Father { // 静态变量 public static String f_StaticField = "父类--静态变量"; protected int i = 1; protected int j = 8; // 变量 public String f_Field = "父类--变量"; // 静态初始化块 static { System.out.println(f_StaticField); System.out.println("父类--静态初始化块"); } // 初始化块 { System.out.println(f_Field); System.out.println("父类--初始化块"); } // 构造方法 public Father() { System.out.println("父类--构造器"); System.out.println("i=" + i + ", j=" + j); j = 9; } }
子类:
package com.ttbank.flep.file.test; public class Son extends Father { // 静态变量 public static String s_StaticField = "子类--静态变量"; // 变量 public String s_Field = "子类--变量"; // 静态初始化块 static { System.out.println(s_StaticField); System.out.println("子类--静态初始化块"); } // 初始化块 { System.out.println(s_Field); System.out.println("子类--初始化块"); } // 构造器 public Son() { System.out.println("子类--构造器"); System.out.println("i=" + i + ",j=" + j); } // 程序入口 public static void main(String[] args) { new Son(); } }
执行结果:
结论:执行的大致顺序如下,
(1) 在一个不存在继承的类中:初始化static变量,执行static初始化块-->初始化普通成员变量(如果有赋值语句),执行普通初始化块-->构造方法
(2)在一个存在继承的类中:初始化父类static成员变量,运行父类static初始化块-->初始化子类static成员变量,运行子类static初始化块-->初始化父类实例成员变量(如果有赋值语句),执行父类普通初始化块-->父类构造方法-->初始化子类实例成员变量(如果有赋值语句)及普通初始化块-->子类构造方法。
参考文献:https://blog.csdn.net/xyajia/article/details/80922329