Java类加载及实例化的调用顺序
标题起得略拗口,大概意思就是说在一个Java类中,域和构造方法的调用顺序。
1. 没有继承的情况
单独一个类的场景下,初始化顺序为依次为 静态数据,继承的基类的构造函数,成员变量,被调用的构造函数。
其中静态数据只会初始化一次。
package com.khlin.binding.test; public class App2 { public static void main(String[] args) { Son son = new Son(); } } class Son { public Son() { System.out.println("this is son."); } public Son(int age) { System.out.println("son is " + age + " years old."); } private Height height = new Height(1.8f); public static Gender gender = new Gender(true); } class Height { public Height(float height) { System.out.println("initializing height " + height + " meters."); } } class Gender { public Gender(boolean isMale) { if (isMale) { System.out.println("this is a male."); } else { System.out.println("this is a female."); } } }
输出:
2. 继承的情况
稍微修改一下代码,添加两个基类,让Son继承Father, Father继承Grandpa。
继承的情况就比较复杂了。由于继承了基类,还将往上回溯,递归地调用基类的无参构造方法。
在我们的例子中,在初始化静态数据后,会先往上追溯,调用Father的默认构造方法,此时再往上追溯到Grandpa的默认构造方法。
注:如果在子类的构造方法中,显式地调用了父类的带参构造方法,那么JVM将调用指定的构造方法而非默认构造方法。
基类和子类均有静态数据,成员变量和构造方法的场景
我们继续修改代码,让其最终呈现如下:
1 package com.khlin.binding.test; 2 3 public class App2 { 4 public static void main(String[] args) { 5 Son son = new Son(); 6 } 7 } 8 9 class Grandpa { 10 public Grandpa() { 11 System.out.println("this is grandpa."); 12 } 13 14 public Grandpa(int age) { 15 System.out.println("grandpa is " + age + " years old."); 16 } 17 18 private Height height = new Height(1.5f); 19 20 public static Gender gender = new Gender(true, "grandpa"); 21 } 22 23 class Father extends Grandpa { 24 25 public Father() { 26 System.out.println("this is father."); 27 } 28 29 public Father(int age) { 30 System.out.println("father is " + age + " years old."); 31 } 32 33 private Height height = new Height(1.6f); 34 35 public static Gender gender = new Gender(true, "father"); 36 } 37 38 class Son extends Father { 39 40 public Son() { 41 super(50); 42 System.out.println("this is son."); 43 } 44 45 public Son(int age) { 46 System.out.println("son is " + age + " years old."); 47 } 48 49 private Height height = new Height(1.8f); 50 51 public static Gender gender = new Gender(true, "son"); 52 } 53 54 class Height { 55 public Height(float height) { 56 System.out.println("initializing height " + height + " meters."); 57 } 58 } 59 60 class Gender { 61 public Gender(boolean isMale) { 62 if (isMale) { 63 System.out.println("this is a male."); 64 } else { 65 System.out.println("this is a female."); 66 } 67 } 68 69 public Gender(boolean isMale, String identify) { 70 if (isMale) { 71 System.out.println(identify + " is a male."); 72 } else { 73 System.out.println(identify + " is a female."); 74 } 75 } 76 }
最后输出会是什么呢?
参考下面另一个案例的分析。链接:http://bbs.csdn.net/topics/310164953
在我们的示例中,加载顺序应该是这样的:
Grandpa 静态数据
Father 静态数据
Son 静态数据
Grandpa 成员变量
Grandpa 构造方法
Father 成员变量
Father 构造方法
Son 成员变量
Son 构造方法
所以输出如下: