继承与初始化

了解包括继承在内的初始化全过程:

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文件中):

  1. 在加载的过程中,编译器注意到Beetle类有一个基类(这是由关键字extends得知的),于是加载器就会去加载这个基类。
  2. 如果基类还有其自身的基类,那么第二个基类就会被加载,如此类推,直到找到根基类。
  3. 找到根基类后,就会执行根基类中的静态初始化(在上例中为Insect类),然后是下一个导出类的静态初始化,以此类推。采用这种由上至下的初始化方式,是因为导出类的静态初始化可能依赖于基类成员是否被正确初始化。

至此为止,必要的类都已经加载完毕,对象就可以被创建了:

  1. 首先,对象中所有的基本类型成员都会被设为默认值,对象引用被设置为null——这是通过将对象内存设为二进制0值而一举生成的;
  2. 然后,基类的构造器会先被调用;
  3. 在基类的构造器完成后,实例变量按其次序被初始化(普通初始化);
  4. 最后,本类构造器的其余部分被执行。

 

当有继承关系时,类成员的初始化顺序为:

基类构造函数 > 静态成员变量 = 静态代码块 > 非静态成员变量 = 非静态代码块 > 构造函数

 

相关内容:(->)类成员变量的初始化