父类A
public class A {
private int i = 9;
protected int j;
public A(){
System.out.println("i = "+i+", j= "+j);
j = 39;
}
private static int x1 = printInit("static A.x1 initialized");
private int x2 = printInit("static A.x2 initialized");
static int printInit(String s){
System.out.println(s);
return 47;
}
}
子类B
public class B extends A {
private int k = printInit("B.k initialized");
public B() {
System.out.println("k = " + k);
System.out.println("j = " + j);
}
private static int x2 = printInit("static B.x2 initialized");
public static void main(String[] args) {
System.out.println("B constructor");
B b = new B();
}
}
运行main输出如下
static A.x1 initialized
static B.x2 initialized
B constructor
static A.x2 initialized
i = 9, j= 0
B.k initialized
k = 47
j = 39
下面看一下运行过程,1、访问B.main方法 于是编译器开始启动并找出B类的编译代码(B.class),加载过程中发现B类有基类A(通过extend得知),于是它继续加载。
2、如果A类自身还有基类,那么第二个基类也会被加载,以此类推。
3、根基类中的static初始化(此例中为A)即会被执行,然后是下一个导出类,此例是B。此方式很重要,因为导出类的static初始化可能会依赖于基类成员能否被正确初始化。
4、至此,所有类加载完,对象就可以被创建了。首先,对象中所有的基本类型都会被设为默认值,对象引用被设为null一一这是通过将对象内存设为二进制零值而一举生成的。任何基类的构造器会被调用。在本例中,它是被自动调用的。但也可以用super来指定对基类构造器的调用(正如在B()构造器的第一步操作)。基类构造器和导出类的构造器一样,以相同的顺序来经历相同的过程。在基类构造器完成后,实例变量按其次序被初始化。最后,构造器的其余部分被执行。