在Java中,所有文件都是一个类,类的初始化无处不在。那么,Java在类初始化时到底做了什么呢?在此记录一个小练习,通过输出,我们可以比较清晰地看出Java在类的初始化时,工作顺序是怎样的。
1 public class Insect { 2 3 private int i = 9; 4 protected int j ; 5 public Insect() { 6 // TODO Auto-generated constructor stub 7 print("i =" + i + ", j = " + j ); 8 j = 39; 9 } 10 11 private static String x1 = print("static Insect.x1 initialized"); 12 13 private static String print(String str){ 14 System.out.println(str); 15 return "47"; 16 } 17 18 } 19 20 public class Beetle extends Insect{ 21 private String k = print("Beetle.k initialize"); 22 private static String t = print("static Beetle.k initialize"); 23 public Beetle() { 24 print("k =" + k); 25 print("j =" + j); 26 } 27 28 public static void main(String[] args) { 29 print("Beetle.k initialize start"); 30 Beetle beetle = new Beetle(); 31 } 32 33 private static String print(String str){ 34 System.out.println(str); 35 return "48"; 36 } 37 38 }
运行上面的程序,会输出以下结果:
static Insect.x1 initialized
static Beetle.k initialize
Beetle.k initialize start
i =9, j = 0
Beetle.k initialize
k =48
j =39
下面,我们对输出结果进行一下分析。
首先,上面有两个类,一个Insect,一个Beetle,其中Insect是Beetle的父类。其中入口是Beetle父中的main方法。
程序首先会想要执行main方法,但是它在加载Beetle方法时,会发现Beetle是有父类的。所以它会转到父类,先加载父类。
所以程序的第一步是执行第11行,private static String x1 = print("static Insect.x1 initialized"); 初始化 static成员;
加载完父类Insect之后,程序会开始加载子类Beetle,因此第二步会执行第22行,private static String t = print("static Beetle.k initialize");初始化 子类的static成员;
完成之后,程序终于进入了main方法,于是执行了第29行,print("Beetle.k initialize start");直接输出;
接着要获取Beetle实例,即会调用Beetle的构造方法。但是Beetle是有父类的,所以程序会先调用父类的构造方法第7、8行 , 输出i和j的值;
在构造了父类之后,程序再构造子类,但是在执行构造方法前,会先完成成员的构造,所以会先执行第21行,private String k = print("Beetle.k initialize");初始化String k;
最后,程序才会执行Beetle的构造方法,执行第24、25行,创建一个Beetle对象,对输出k和j的值。
Done