看一段代码先
<!-- lang: java -->
public class Test {
//
public Test() {
init();
System.out.println("无参构造方法");
}
public Test(int i) {
init();
System.out.println("整数参数构造方法" + i);
}
public Test(String str) {
init();
System.out.println("字符串参数构造方法" + str);
}
public void init_Test() {
// 做一些变量的初始化或者对象所需要的环境创建工作
}
}
采用构造代码块的实现
<!-- lang: java -->
public class Test {
{
// 做一些变量的初始化或者对象所需要的环境创建工作
}
public Test() {
System.out.println("无参构造方法");
}
public Test(int i) {
System.out.println("整数参数构造方法" + i);
}
public Test(String str) {
System.out.println("字符串参数构造方法" + str);
}
}
第二段的代码无非是把共同的逻辑,init_Test()放到了{}之中,这种实现就叫做构造代码块。
理解一下定义
代码块:用大括号把多行代码封装在一起,形成一个独立的数据体,实现特定算法的集合,这样一个就是代码块,说白了就是大括号括起来的这样一个结构。 Java中包含4种代码块: 1:普通代码块,方法体之后的这种结构,太常见了,不多说。 2:静态代码块,有人称之为静态块,static 后跟着{ }这样一种结构,常用于静态变量的初始化或对象创建之前的环境初始化。 3:同步代码块:synchronized关键字修饰的,它表示同一时间只能有一个线程进入其中,是一种多线程保护机制。 4:构造代码块:在类中,没有任何前缀或后缀,直接用{},这样一种结构就是构造代码块。
构造代码块的几个问题
众所周知,每一个类都有一个构造函数,而且至少有一个,如果没有特意声明,那么编译器会自动创建一个无参构造函数,然后再生成对象的时候调用这个构造函数。那么我们需要解决如下几个问题: 1:构造函数和构造代码块是什么关系? 2:构造代码块何时执行? 3:构造代码块的原理是什么? 4:构造代码块的目的或者说应用场景又是什么?
解释:
编译器在看到构造代码块的时候,会把构造代码块插入到每个构造器的最前端。每次new 一个实例的时候会首先执行构造代码块,而后执行构造函数内部的逻辑,说白了,构造代码块就是构造函数内部首先执行的逻辑块。
应用场景
1:如果每个构造方法都有一个共同的逻辑:初始化变量,我们可能想到把共同的逻辑提取到一个方法中,然后在每一个构造方法中调用就可以,但是还有更好的形式:构造代码块,利用了构造代码块,我们不需要调用,不需定义新的方法,编译器替我们实现我们想要达到的目的,而且代码看起来更加的优雅
2:有时候,我们创建的对象需要依靠某种环境才能够存在,如果该环境不存在,则手动创建一个。
以上两个点其实是一样的,无非就是在构造器之中具有共同需要执行的逻辑,而且这个业务逻辑的优先级别是第一等的,当遇到构造函数具有共同逻辑的时候,采取构造代码块会让程序更加的优雅,当然,构造函数还是应该尽量的简单。 根据功能的不同,可以编写多个构造代码块,当然构造代码块的顺序,必须是业务逻辑的顺序才行。
特殊情况
凡事皆有特例,生活之中如此,技术上也不例外。
当一个构造方法采取this的方式来调用其它构造方法的时候,这时,不会插入构造代码块,也就是说,在这两个构造函数执行期间,Java编译器会发现内部的这个构造方法(this代表的那个构造方法)已经调用过一次构造代码块了,这时,外部的这个就不会再调用第二次构造代码块了。
我们要回到创建构造代码块的根本目的来说:构造代码块无非就是把个构造函数共同的逻辑提取出来,提前执行而已。既然是共同逻辑,那么只要执行一次即可。
除了this,还有super
总之
我们只要记住,构造代码块是构造函数的共同逻辑,会在构造函数内部逻辑之前执行,而且只会执行一次,这样就足够了。