1. 引言
了解Java初始化的顺序,有助于理解Java的初始化机制和内存机制。
顺序:父类static变量->子类static变量->父类成员变量->父类构造器->成员变量->构造器->main函数(说明:static变量包括static变量和static代码块,按位置顺序执行)
2. 样例
2.1 无继承的类的初始化顺序
public class TestClass { public static void main(String[] args) { // TODO Auto-generated method stub System.out.println("Creating new Cupboard() in main"); new Cupboard(); System.out.println("Creating new Cupboard() in main"); new Cupboard(); t2.f2(1); t3.f3(1); } static Table t2 = new Table(); static Cupboard t3 = new Cupboard(); } // : StaticInitialization.java // Specifying initial values in a // class definition. class Bowl { Bowl(int marker) { System.out.println("Bowl(" + marker + ")"); } void f(int marker) { System.out.println("f(" + marker + ")"); } } class Table { static Bowl b1 = new Bowl(1); static{ System.out.println("Table() static 1"); } Table() { System.out.println("Table()"); b2.f(1); } void f2(int marker) { System.out.println("f2(" + marker + ")"); } Bowl b10 = new Bowl(10); { System.out.println("Table() non-static"); } Bowl b11 = new Bowl(11); static Bowl b2 = new Bowl(2); static{ System.out.println("Table() static 2"); } } class Cupboard { Bowl b3 = new Bowl(3); static Bowl b4 = new Bowl(4); Cupboard() { System.out.println("Cupboard()"); b4.f(2); } void f3(int marker) { System.out.println("f3(" + marker + ")"); } static Bowl b5 = new Bowl(5); }
输出的结果如下:
Bowl(1) Table() static 1 Bowl(2) Table() static 2 Bowl(10) Table() non-static Bowl(11) Table() f(1) Bowl(4) Bowl(5) Bowl(3) Cupboard() f(2) Creating new Cupboard() in main Bowl(3) Cupboard() f(2) Creating new Cupboard() in main Bowl(3) Cupboard() f(2) f2(1) f3(1)
2.2 有继承的类的初始化顺序
//: Beetle.java // The full process of initialization. class Insect { int i = 9; int j; Insect() { prt("i = " + i + ", j = " + j); j = 39; } static{ System.out.println("Insert static block0"); } static int x1 = prt("static Insect.x1 initialized"); static int prt(String s) { System.out.println(s); return 47; } static{ System.out.println("Insert static block1"); } } public class Beetle extends Insect { int k = prt("Beetle.k initialized"); Beetle() { prt("k = " + k); prt("j = " + j); } static int x2 = prt("static Beetle.x2 initialized"); static int prt(String s) { System.out.println(s); return 63; } public static void main(String[] args) { prt("Beetle constructor"); //flag 1 Beetle b = new Beetle(); //flag 2 } } ///:~
输出的结果如下:
Insert static block0 static Insect.x1 initialized Insert static block1 static Beetle.x2 initialized Beetle constructor i = 9, j = 0 Beetle.k initialized k = 63 j = 39 //如果只把flag 1 那条语句注释掉,输出内容如下: Insert static block0 static Insect.x1 initialized Insert static block1 static Beetle.x2 initialized i = 9, j = 0 Beetle.k initialized k = 63 j = 39 //如果只把flag 2 那条语句注释掉,输出内容如下: Insert static block0 static Insect.x1 initialized Insert static block1 static Beetle.x2 initialized Beetle constructor
3. 总结
只要按照这个顺序:父类static变量->子类static变量->父类成员变量->父类构造器->成员变量->构造器->main函数(说明:static变量包括static变量和static代码块,按位置顺序执行), 去推导初始化执行顺序就能得到正确的执行答案数据。
注意点:
1.若仅仅执行static方法,则只会执行该类及其父类的所有静态变量,而且静态变量只会被执行一次
2.当对象被new出来时,才会开始初始化该类及其父类的所有变量,按照以上的说的顺序执行
3.成员或者静态static变量若申明时不赋值,会被初始化相应类型的默认值,例如int是0,String是null等
4.可以用debug模式直接断点调试,跟着走一遍,就能看到代码是怎么初始化变量的(当然,自己先演练一遍,效果更好)
4.参考
Thinking in Java P113, P158