要说起Java中成员变量的初始化,可以说是最基本的操作了,然而其中也大有文章,非常值得注意。
内联初始化
内联初始化是最简单的初始化方法,直接在声明成员变量的时候赋值初始化即可。
public class Bar {
private int foo = 10;
}
内联初始化简洁明了,方便实用,但是如果变量初始化时需要异常处理、条件判断等复杂操作,就有心无力了。
构造函数初始化
如果初始化变量时有一些复杂的逻辑,比如首先正常取值,在取值失败时再采用默认值,这时可以考虑将其放到构造函数中:
public class Bar {
private int foo;
public Bar() {
try {
this.foo = Foo.getFoo();
} catch (Exception e) {
this.foo = 5;
}
}
}
同时,如果有多个构造函数,则应该将相同的部分放到一个函数中,在构造函数中复用。
public class Bar {
private int foo;
public Bar() {
this.initFoo();
}
public Bar(int bar) {
this.initFoo();
}
private void initFoo() {
try {
this.foo = Foo.getFoo();
} catch (Exception e) {
this.foo = 5;
}
}
}
注意到initFoo函数修饰符为private,因为如果它不是private或者final,根据Java多态的特性,如果Bar有了子类,并且子类override了initFoo方法,那么构造子类时,会自动调用Bar的构造方法,此时会调用子类的initFoo方法,产生意想不到的效果。
因此initFoo如果不需要被子类复用,可以设置为private
,如果需要被子类复用,可以设置为protected final
。
初始化块
大家对于Java的static初始化块应该很熟悉了,就是下面这样的:
public class Bar {
static {
}
}
其实,把static关键字去掉,就是Java实例初始化块。编译器会把初始化块复制到每个构造函数中,因此非常适合在多个构造函数中共享代码。
public class Bar {
private int foo;
public Bar() {
}
public Bar(int bar) {
}
{
try {
this.foo = Foo.getFoo();
} catch (Exception e) {
this.foo = 5;
}
}
}
可以看到,既达到了代码复用的目的,还少写了一个函数,可谓一举两得。