诠释了继承类之间构造器(有参、无参)、对象初始化块和静态初始化块之间的关系及调用顺序

来源:互联网 发布:js 文本框 数值合计 编辑:程序博客网 时间:2024/05/21 00:15

首先得明白对象初始化块和静态初始化块是什么?

对象初始化块即初始化块,就是在类中用{}括起来的语句,一个类中可以包含多个,同理,静态代码块就是在{}前面加一个static标记。

只不过对象初始化块在构造类的对象时被执行,而静态初始化块在类被加载时调用。

下面看一个例子:

public class A extends B {{System.out.println(5);}static {System.out.println(6);}public A() {this(8);System.out.println(7);}public A(int i) {System.out.println(i);}{System.out.println(9);}public static void  main(String[] args) {new B(); // 打印什么?// new A(); // 打印什么?}}class B {int x;{System.out.println(1);}static {System.out.println(2);}public B() {this(4);System.out.println(3);}public B(int i) {System.out.println(i);}{System.out.println(10);}}
可以试着想一想打印顺序是什么,然后再去验证一下。

仔细思考过后,来想一想为什么


首先得清楚两点:1. 类 A 继承类 B; 2. main方法在类 A 中。

首先 new B()打印的是: 2、6、1、10、4、3 

之前说过,静态初始化块随着类加载而调用,构造 B 的对象首先得加载类 B,所以先打印了 2。

乍一看可能不明白为什么有 6 打印出来啊?前文说了注意的两点,就是第二点:main方法在类 A 中,所以打印 6。假设main方法放到第三个类中,就没有 6。

ps:这里可能会有人很疑惑:为什么先打印 2,而不是 6?不是应该先加载main方法吗?可是别忘了类 A 是继承于类 B 的,所以咯。

然后构造了类 B 的对象,所以 B 的对象初始化块被调用,即打印 1。

接着打印 10。 这里需要注意:不管是对象初始化块还是静态初始化块都按代码编写顺序执行,所以是 1 --> 10 的顺序。

接下来就真正到了构造类 B 的对象了,即构造器调用,无参先调了有参,所以先打印 4,然后才是 3。

到此第一个打印结束。


下面看看new A()的打印: 2、6、1、10、4、3、5、9、8、7 

前面都是一样,因为类 A继承类 B,所以仍旧先加载类 B。

因为调的是 A 的无参构造器,而子类无参构造器第一行默认是调用父类无参构造器,调用构造器必然涉及对象构造,

所以 B 的对象初始化块先被调用,接着是 B 的构造器调用,所以调用顺序2、6、1、10、4、3,

到这为止才回到构造 A 对象,所以紧接着调用类 A 的对象初始化块,即 5、9。

最后才终于回到最终调用的类 A 无参构造器,里边首先又调用了有参构造器,所以打印是:8、7。

到此结束。



0 0
原创粉丝点击