Java初始化块及构造函数调用顺序

Java类中的初始化块,可以有静态和非静态两种。

 

静态初始化块中的语句,在类首次被加载时执行。

 

非静态初始化块中的语句,如同写在类的每一个构造函数的开始处,因此当调用构造函数时,非静态初始化块中的语句会被执行到。

 

使用非静态初始化块,可以简化构造函数的编写,不必在每个构造函数中写入同样的语句。

 

 

 

下面谈谈继承结构下的构造函数调用以及成员初始化。

 

Java中通过new 语句调用类的构造函数建立该类的一个对象。那么,具体的情况是怎样的?

假定继承关系是 A继承B继承C

 

首先,建立类A的对象,java解释器会查找类路径,定位A.class文件, 接着定位A的父类B对应的B.class文件,再定位B的父类C C.class,递归这个过程,直到Object~

 

接着,沿着继承链从父类到子类(CBA),挨个执行静态初始化块。

 

然后,沿着继承链从父类到子类(CBA),挨个初始化域、非静态初始化块。

 

最后,执行C的构造函数,再B的构造函数,A的构造函数,构造过程完毕。

 

可以看一个例子:

public class ConstructorSequence {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		new A();
	}

}



class A extends B{
	
	public A() {
		System.out.println("9.Constructor A");
	}
	
	// Non-static initialization block of Class A
	{
		System.out.println("8.Non-static initialization block in A");
	}
	
	// Static initialization block of Class A
	static {
		System.out.println("3.Static initialization block in A");
	}
}

class B extends C{
	public B() {
		System.out.println("7.Constructor B");
	}
	
	// Non-static initialization block of Class B
	{
		System.out.println("6.Non-static initialization block in B");
	}
	
	// Static initialization block of Class B
	static {
		System.out.println("2.Static initialization block in B");
	}
}


class C{
	public C() {
		System.out.println("5.Constructor C");
	}
	
	// Non-static initialization block of Class C
	{
		System.out.println("4.Non-static initialization block in C");
	}
	
	// Static initialization block of Class C
	static {
		System.out.println("1.Static initialization block in C");
	}
}


运行结果为

1.Static initialization block in C
2.Static initialization block in B
3.Static initialization block in A
4.Non-static initialization block in C
5.Constructor C
6.Non-static initialization block in B
7.Constructor B
8.Non-static initialization block in A
9.Constructor A


 

 

 

一个注意点:

如果在构造函数内部调用其他函数(尤其是可能被子类覆盖的函数),由于多态的存在,父类构造函数中很可能调用的是子类中的方法,而子类有可能还没完成初始化工作

故而,Thinking in Java中提及过,如果可能,尽量避免在构造函数中调用其他方法(父类的private final方法除外,二者只会有唯一版本,杜绝了多态可能)。

 

顺便说下,类的构造函数可以使用this关键字调用重载的其他构造函数,或者使用super关键字调用父类的构造函数,

二者最多出现一个,而且必须位于构造函数内的第一条语句,否则编译不过。

 

如果第一句既不是this,也不是super,那么编译器会默认添加一条super();调用父类的无参构造函数——这就是为什么用于继承的父类最好显式提供一个无参构造函数的原因。

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值