最近工作不忙,闲来无事,就看看书,今天遇到了构造代码块让我一顿好奇。构造函数倒是了解一些,构造代码块还是第一次听说,那么到底什么是构造代码块?
其实,构造代码块是代码块的一种类型。代码块是指用大括号把多行代码封装在一起,形成一个独立的数据体,实现特定算法的代码集合。一般来说,代码块是不能单独运行,必须要有运行主体。在Java中一共有四种类型的代码块,即:
1、普通代码块:就是在方法后面使用“{}”括起来的代码片段,它不能单独运行,必须通过方法名调用执行。
2、静态代码块:在类中使用static修饰,并使用“{}”括起来的代码片段,用于静态变量的初始化或对象创建前的环境初始化。
3、同步代码块:使用synchronized关键字修饰,并使用“{}”括起来的代码片段,它表示同一时间只能有一个线程进入到该方法中,是一种多线程保护机制。
4、构造代码块:在类中没有任何前缀或后缀,并使用“{}”括起来的代码片段。
从这个命名就可以看出构造代码块和构造函数肯定有一定的关系,那么究竟是什么关系呢?在回答这个问题之前,我们先要知道Java编译器是如何处理构造代码块的,下面通过一个实例来说明:
public class DemoA { //构造代码块 { System.out.println("执行构造代码块"); } public DemoA(){ System.out.println("执行无参构造函数"); } public DemoA(String str){ System.out.println("执行有参构造函数,参数:" + str); } public static void main(String args[]){ new DemoA(); new DemoA("construct code block"); } }
运行这个demo后,在控制台输出的信息如下:
执行构造代码块
执行无参构造函数
执行构造代码块
执行有参构造函数,参数:construct code block
从我用红色标出来的打印信息可以看出,Java编译器在处理构造代码块的时候,是直接把它插在每个构造函数的最前面,执行完构造代码块里面的内容后,再执行构造函数中的内容。
根据这个实例,就可以很好的回答构造代码块与构造函数之间的关系:构造代码块会在每个构造函数内首先执行,这里需要注意的是构造代码块不是在构造函数之前先执行,它是依托构造函数执行的。
DemoA这个实例说明了构造代码块与构造函数之间的关系,那有没有特例呢?还是通过一个实例来证明,这个实例的作用统计一个类的实例数量。
public class CountObjectInstanceNum { public static void main(String[] args){ new Base(); new Base("AAA"); new Base(100); System.out.println("The number of object instance is " + Base.getNumOfObjects()); } } class Base{ //对象计数器 private static int numOfObjects = 0; { //构造代码块,计算产生的对象数量 numOfObjects++ ; } public Base(){ System.out.println("I am a constructor without parameter"); } public Base(String str){ //有参构造函数调用无参构造函数 this(); System.out.println("I am a constructor with having parameter: " + str); } public Base(int m){ System.out.println("I am a constructor with having parameter: " + m); } public static int getNumOfObjects(){ return numOfObjects; } }
这个实例运行结构如下:
I am a constructor without parameter
I am a constructor without parameter
I am a constructor with having parameter: AAA
I am a constructor with having parameter: 100
The number of object instance is 3
根据DemoA这个实例得出的结论,CountObjectInstanceNum统计出来的实例应该是4 ,而红色标出的却是3。这就说明了上面所提出的结论是存在特例的情况的,即:如果遇到this关键字(也就是构造函数调用自身其他的构造函数时)则不插入构造代码块。
如果是super关键字呢,在构造代码块的处理上,super方法没有任何特殊的地方,编译器只会把构造代码块插入到super关键字方法之后执行,有兴趣的朋友可以试试。