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

本文通过一个Java示例程序详细解析了类的构造器、初始化块及super关键字的调用顺序。具体分析了静态成员、普通成员及构造器的初始化过程,并解释了为何子类构造器中super关键字的调用会导致父类构造器的不同顺序。

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

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语句其实已经执行过了,不会重复执行。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值