想知道流程是怎样的,最简单的方法就是在每一个必要的地方输出一下,类似下断点去debug一样。考虑如下例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | //author: Neeke Blog:www.ineeke.com public class Insect{ private int i = 20; protected int j; Insect(){ System.out.println("i = " + i + ", j = " + j); j = 22; } private static int x1 = printInit("静态的Insecct.x1初始化"); static int printInit(String s){ System.out.println(s); return 40; } } public class Beetle extends Insect{ private int k = printInit("Beetle.k初始化"); public Beetle(){ System.out.println("k = " + k); System.out.println("j = " + j); } private static int x2 = printInit("静态的Beetle.x2初始化"); public static void main(String[] args){ System.out.println("Beetle构造"); Beetle b = new Beetle(); } } |
程序输出结果:
静态的Insect.x1初始化
静态的Beetle.x2初始化
Beetle构造
i = 20, j = 0
Beetle.k初始化
k = 40
j = 22
执行这段Java程序时第一件事是要访问Beetle.main()(一个静态方法),所以加载器便去寻找已编译的Beetle.class文件。在这个加载过程中,加载器通过extends关键字得知它还有一个父类Insect,于是又接着去加载这个父类。值得注意的是,无论你是否实例化了这个父类,这件事都会在加载器中发生。
如果Insect还存在一个父类,那么这第二个父类也将被载入,以此类推。
接下来,静态属性开始在根类(此例中是Insect)中初始化,接着是它的子类,以此类推。这一点非常重要,因为子类的静态初始化很可能依赖于父类成员属性被初始化之后。
此时,所有必要的类都已经被载入,可以创建对象了。首先,该对象中所有的原始数据类型都被置为其初始值,并且对象的引用被置为null。接着,父类的构造方法被调用。在上面的例子中,这个调用是自动的,当然,你也可以在Beetle()构造方法的第一行操作代码中通过super关键字显示的调用。父类的构造与子类有相同的过程及顺序。在父类构造完成后,实例变量被初始化。最终,子类构造方法中的其余部分开始被执行。

