继承与初始化
- 2021 年 4 月 14 日
- 筆記
- Java编程思想, 有继承时的初始化顺序
了解包括继承在内的初始化全过程:
class Insect { private int i = printInit("Insect.i initialized");; protected int j; Insect() { System.out.println("i= " + i + ", j= " + j); j = 39; } private static int x1 = printInit("static Insect.x1 initialized"); static int printInit(String s) { System.out.println(s); return 47; } } public class Beetle extends Insect { private int k = printInit("Beetle.k initialized"); public Beetle() { System.out.println("k= " + k); System.out.println("j= " + j); } private static int x2 = printInit("static Beetle.x2 initialized"); public static void main(String[] args) { System.out.println("Beetle constructor"); Beetle b = new Beetle(); } }
执行结果:
"C:\Program Files\Java\jdk1.8.0_91\bin\java.exe" ... static Insect.x1 initialized static Beetle.x2 initialized Beetle constructor Insect.i initialized i= 47, j= 0 Beetle.k initialized k= 47 j= 39 Process finished with exit code 0
程序运行时,先试图访问Beetle.main()(一个static方法),访问Beetle类的静态方法将会使Beetle类加载,即加载器开始启动并找出Beetle类的编译代码(在名为Beetle.class文件中):
- 在加载的过程中,编译器注意到Beetle类有一个基类(这是由关键字extends得知的),于是加载器就会去加载这个基类。
- 如果基类还有其自身的基类,那么第二个基类就会被加载,如此类推,直到找到根基类。
- 找到根基类后,就会执行根基类中的静态初始化(在上例中为Insect类),然后是下一个导出类的静态初始化,以此类推。采用这种由上至下的初始化方式,是因为导出类的静态初始化可能依赖于基类成员是否被正确初始化。
至此为止,必要的类都已经加载完毕,对象就可以被创建了:
- 首先,对象中所有的基本类型成员都会被设为默认值,对象引用被设置为null——这是通过将对象内存设为二进制0值而一举生成的;
- 然后,基类的构造器会先被调用;
- 在基类的构造器完成后,实例变量按其次序被初始化(普通初始化);
- 最后,本类构造器的其余部分被执行。
当有继承关系时,类成员的初始化顺序为:
基类构造函数 > 静态成员变量 = 静态代码块 > 非静态成员变量 = 非静态代码块 > 构造函数
相关内容:(->)类成员变量的初始化