1.类初始化阶段,类执行最顶层父类的静态初始化块,依次向下,最后执行当前类静态初始化块。
class Root { static{ //静态初始化块 System.out.println("Root的静态初始化块"); } { //普通初始化块 System.out.println("Root的普通初始化块"); } }class Mid extends Root{ static{ System.out.println("Mid的静态初始化块"); } { ystem.out.println("Mid的普通初始化块"); } }class Leaf extends Mid{ static{ System.out.println("Leaf的静态初始化块"); } { System.out.println("Leaf的普通初始化块"); } }public class test{ public static void main(String[] args) { new Leaf(); }}
如上,首先执行顶层父类Root的静态初始化块,然后依次向下,即是Mid,和leaf的静态初始化块.然后再执行顶层父类Root的普通初始化块与构造器。
静态初始化块是类相关的,系统将在类初始化阶段执行静态初始化块,而不是在创建对象时才执行。因此静态初始化块总是比普通初始化块先执行。 另外,一旦某类的类初始化成功后,该类就会在虚拟机中一直存在,因此第二次创建该类的实例时,无需再次对该类进行类初始化如例5中的 new Leaf(); new Leaf(); 第一次new Leaf()时系统会自动初始化Leaf类,完成后再次创建Leaf实例时,就无需再进行类初始化步骤,即无需再输出处于该步骤的静态初始化块的内容。 总而言之,两次new Leaf()只输出一次静态初始化块的内容。
2.对象初始化阶段,先执行最顶层父类的普通初始化块、构造器,依次向下,最后执行当前类普通初始化块、构造器。
class Root { { //普通初始化块 System.out.println("Root的普通初始化块"); } public Root() { System.out.println("Root的无参数的构造器"); }}class Mid extends Root{ { System.out.println("Mid的普通初始化块"); } public Mid() { System.out.println("Mid的无参数的构造器"); } }class Leaf extends Mid{ { System.out.println("Leaf的普通初始化块"); } public Leaf() { System.out.println("执行Leaf的构造器"); }}public class test{ public static void main(String[] args) { new Leaf(); }}如上代码,程序先执行顶层父类Root中的普通初始化块,再执行Root的构造器。这里有点注意的是, 执行顺序与初始化块和构造器在类中 的相对 位置无关。若类中的构造器在普通初始化块之前,对象初始化时依旧先执行普通初始化块,再执行构造器。
然后再依次执行Mid类的普通初始化块、构造器;最后执行Leaf类的普通初始化块、构造器。
3.构造器.
class Root { public Root() { System.out.println("Root的无参数的构造器"); }}class Mid extends Root{ public Mid() { System.out.println("Mid的无参数的构造器"); } public Mid(String msg) { System.out.println("Mid的带参数构造器,其参数值:" + msg); }}class Leaf extends Mid{ public Leaf() { System.out.println("执行Leaf的构造器"); }}public class test{ public static void main(String[] args) { new Leaf(); }}
创建对象时,如果子类的构造器中没有通过super调用父类的有参构造器,也没有通过this调用自身的其他构造方法,则系统会默认先调用父类的无参构造器。 为了方便起见,可以当做每个无参构造器中都有一句super();
如上代码,需要创建Leaf类的实例时,系统会自动调用顶层父类Root的无参构造器,然后依次向下调用各父类的无参构造器,即Mid(),最后调用本身的Leaf(). 因此最后输出为: Root的无参数的构造器 Mid的无参数的构造器 执行Leaf的构造器
4.调用父类构造器.
class Root{ public Root() { System.out.println("Root的无参数的构造器"); }}class Mid extends Root{ public Mid() { System.out.println("Mid的无参数的构造器"); } public Mid(String msg) { //通过this调用同一类中重载的构造器 this(); System.out.println("Mid的带参数构造器,其参数值:" + msg); }}class Leaf extends Mid{ public Leaf() { //通过super调用父类中有一个字符串参数的构造器 super("Struts2权威指南"); System.out.println("执行Leaf的构造器"); }}public class Test{ public static void main(String[] args) { new Leaf(); }}
若无参构造器中调用了重载的有参构造器,则优先执行被调用的有参构造器,不执行无参构造器。
例如上述代码,new Leaf()创建Leaf类的对象时,需要调用Leaf类的构造器,而Leaf()中使用super("Struts2权威指南")调用了父类Mid的有参构造器Mid(String msg)。而Mid(String msg)中又通过this()调用了自身的无参构造器Mid(),根据例3中的结论,得知系统可通过Mid()自动调用父类Root的无参构造器Root()输出: Root的无参数的构造器 Mid的无参数的构造器 Mid的带参数构造器,其参数值:Struts2权威指南 执行Leaf的构造器
5.初始化块与构造器混合时.
class Root{ static{ System.out.println("Root的静态初始化块"); } { System.out.println("Root的普通初始化块"); } public Root() { System.out.println("Root的无参数的构造器"); }}class Mid extends Root{ static{ System.out.println("Mid的静态初始化块"); } { System.out.println("Mid的普通初始化块"); } public Mid() { System.out.println("Mid的无参数的构造器"); } public Mid(String msg) { //通过this调用同一类中重载的构造器 this(); System.out.println("Mid的带参数构造器,其参数值:" + msg); }}class Leaf extends Mid{ static{ System.out.println("Leaf的静态初始化块"); } { System.out.println("Leaf的普通初始化块"); } public Leaf() { //通过super调用父类中有一个字符串参数的构造器 super("Struts2权威指南"); System.out.println("执行Leaf的构造器"); }}public class Test{ public static void main(String[] args) { new Leaf(); new Leaf(); }}
执行结果: