子类调用父类构造器时的Java类成员初始化顺序

来源:互联网 发布:淘宝找不到自己的品牌 编辑:程序博客网 时间:2024/05/21 10:25

我们先看一个经典的例子:

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();System.out.println("Mid的带参的构造器,其参数值是:" + msg);}}class Leaf extends Mid{static {System.out.println("Leaf的静态初始化块");}{System.out.println("Leaf的普通初始化块");}public Leaf(){super("我的测试");System.out.println("Leaf的无参构造器");} }public class test9{public static void main(String[] args) {new Leaf();new Leaf();}}
它的输出结果如下:

输出结果:Root的静态初始化块Mid的静态初始化块Leaf的静态初始化块Root的普通初始化块Root的无参构造器Mid的普通初始化块Mid的无参构造器Mid的带参的构造器,其参数值是:我的测试Leaf的普通初始化块Leaf的无参构造器Root的普通初始化块Root的无参构造器Mid的普通初始化块Mid的无参构造器Mid的带参的构造器,其参数值是:我的测试Leaf的普通初始化块Leaf的无参构造器

说明:

一,程序第一次编译执行时,会先从基类依次往下加载类,加载类时会初始化静态成员,不调用构造器,加载类和初始化静态成员的动作仅发生一次不会重复执行。加载完毕后才能创建对象。加载类对应输出结果的前三行。

二,很多人对于Mid的无参构造器和有参构造器那里的输出顺序有些迷惑,我是这样理解的:

创建对象时,会先找对应类的构造器(想想构造器名和类名为什么是相同的?),我们new出一个Leaf后,找到Leaf构造器,但并不会马上执行,因为有继承关系,要保证基类先完成初始化,所以会接着找它的父类。这里关键的地方在于,Leaf构造器调用了super("我的测试"),Leaf构造器虽然不会被马上执行,但是程序却知道了这个super("我的测试"),当leaf类的父类Mid类执行本身的构造器时,就会执行有参构造器,参数是"我的测试"。先接着往下看,程序一直找父类直到找到基类Root类。在同一个类中,静态成员(包括代码块)先初始化,然后是非静态成员,最后是构造器。本例中的静态代码块在加载类时已经初始化了,不用重复执行。需要强调的是,这里的初始化顺序的前提是在同一个类中。当有super语句时,就会发生跨类的情况。

所以当执行到Mid类时,先执行普通代码块,然后关键来了,由于Leaf构造器中有super("我的测试")语句,所以Mid类会执行有参构造器,这个有参构造器中有this() 语句,所以会先调用当前对象的无参构造器。之后执行到Leaf构造器时,super语句其实已经执行过了,不会重复执行。

这是我对此程序输出顺序的理解,不知是否准确,希望大神能指点一下。

0 0
原创粉丝点击