前面我们已经对代码块做了相应的介绍说说java中的那些代码块 ,这篇我们主要针对构造代码块来做详细介绍。
先看一个简单的例子:
public class ConstructCodeBlock {
{
System.out.println("构造代码块1");
}
public ConstructCodeBlock(){
System.out.println("构造方法");
}
public ConstructCodeBlock(String name){
System.out.println("有参构造方法");
}
{
System.out.println("构造代码块2");
}
public static void main(String[] args) {
new ConstructCodeBlock();
new ConstructCodeBlock("小明");
}
}
输出结果:
构造代码块1
构造代码块2
构造方法
构造代码块1
构造代码块2
有参构造方法
构造方法与构造代码块
我们知道,一个类中至少有一个构造方法(如果没有,编码器会自动的为其创建一个无参构造方法),构造方法是在对象生产时调用的,从上面的例子我们已经知道,构造代码块是在构造方法前执行的。那么问题来了:构造方法和构造代码块是什么关系呢?构造代码块具体又是什么时候执行呢?
很简单,编译器会把构造代码块插入到每个构造方法的最前端,也就是说上例中的代码等价下面这段代码:
public class ConstructCodeBlock {
public ConstructCodeBlock(){
System.out.println("构造代码块1");
System.out.println("构造代码块2");
System.out.println("构造方法");
}
public ConstructCodeBlock(String name){
System.out.println("构造代码块1");
System.out.println("构造代码块2");
System.out.println("有参构造方法");
}
public static void main(String[] args) {
new ConstructCodeBlock();
new ConstructCodeBlock("小明");
}
}
所以说当我们new一个对象时会先执行构造代码块,然后再执行其他代码,也就是说:构造代码块会在每个构造函数内首先执行(注意:构造代码块不是在构造函数之前执行,它是依托于构造函数的执行)。
构造代码块的作用
一个东西存在必须有它作用,不然就没有存在的意义了,而它的作用也是我们最关心的。那构造代码块有什么用呢?
1、初始化实例变量
如果每个构造方法都要初始化变量,可以通过构造代码块来实现。当然也可以通过定义一个方法,然后在每个构造函数中调用该方法来实现,这样也能解决问题,但之前我们就讨论过构造函数尽量简单化(参考构造函数),如果用构造代码块的方式就不用定义和调用了,会直接由编译器写入到每个构造函数中。
2、初始化实例环境
当一个对象必须在适当的场景下才能存在,如果没有适当的场景,就需要在创建此对象时创建此场景。例如,在JEE开发中,要产生HTTP Request必须首先建立HTTP Session,在创建HTTP Request时就可以通构造代码块来检查HTTP Session是否存在,如果不存在就创建HTTP Session对象。
所以很好的利用构造代码块这两个特性不仅可以减少代码量,还可以让程序更容易阅读,特别是当所有的构造函数都要实现逻辑,而且这部分逻辑又很复杂时,就可以通过编写多个构造代码块来实现。每个代码块完成不同业务逻辑,然后按照业务顺序依次存放,这样在创建实例时JVM也就会按照顺序依次执行,实现复杂对象的模块化创建。
来一个真实的案列:统计一个类的访问数量。我们通过构造代码块实现
public class ConstructCodeBlock {
public static void main(String[] args) {
new TestCount();
new TestCount("小明");
new TestCount(0);
System.out.println("产生实例对象数量为:"+TestCount.getNumofObjects());
}
}
class TestCount{
//对象计数器
private static int numofObjects = 0;
{
//构造代码块,计算产生对象数量
numofObjects++;
}
//无参构造函数
public TestCount(){
}
//有参构造函数调用无参构造函数
public TestCount(String str){
this();
}
//有参构造函数调用无参构造函数
public TestCount(int i){
}
public static int getNumofObjects(){
return numofObjects;
}
}
结果会是多少呢?我们知道编译器会将构造代码块放到构造方法中执行,我们看到在第二个构造函数中使用this()调用了第一个无参构造方法,是不是当我们newTestCount(“小明”)时计数器会执行两次呢?一次执行无参构造函数中的构造代码块,一次执行自身的构造代码块。然而打印的结果是 产生实例对象数量为:3
这是为什么呢,其实并不是每次编译器都会将构造代码块放到构造方法中,有一个特殊情况:如果遇到this关键字(也就是构造方法调用自身其他的构造方法时),编译器将不会在构造代码块放到构造方法中。所以保证了只执行了一次。