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

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

对象初始化块即初始化块,就是在类中用{}括起来的语句,一个类中可以包含多个,同理,静态代码块就是在{}前面加一个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
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值