4.4.2 构建器初始化
字段先初始化,之后才是构造方法;
字段又有static字段先初始化,之后非static初始化(int i;这个就初始化默认值)
class Bowl {
Bowl(int marker) {
System.out.println("Bowl(" + marker + ")");
}
void f(int marker) {
System.out.println("f(" + marker + ")");
}
}
class Table {
static Bowl b1 = new Bowl(1);
Table() {
System.out.println("Table()");
b2.f(1);
}
void f2(int marker) {
System.out.println("f2(" + marker + ")");
}
static Bowl b2 = new Bowl(2);
}
class Cupboard {
Bowl b3 = new Bowl(3);
113
static Bowl b4 = new Bowl(4);
Cupboard() {
System.out.println("Cupboard()");
b4.f(2);
}
void f3(int marker) {
System.out.println("f3(" + marker + ")");
}
static Bowl b5 = new Bowl(5);
}
public class StaticInitialization {
public static void main(String[] args) {
System.out.println(
"Creating new Cupboard() in main");
new Cupboard();
System.out.println(
"Creating new Cupboard() in main");
new Cupboard();
t2.f2(1);
t3.f3(1);
}
static Table t2 = new Table();
static Cupboard t3 = new Cupboard();
} ///:~
Bowl 允许我们检查一个类的创建过程,而Table 和 Cupboard 能创建散布于类定义中的Bowl 的 static 成
员。注意在 static 定义之前,Cupboard 先创建了一个非static 的 Bowl b3。它的输出结果如下:
Bowl(1)
Bowl(2)
Table()
f(1)
Bowl(4)
Bowl(5)
Bowl(3)
Cupboard()
f(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f(2)
f2(1)
f3(1)
static 初始化只有在必要的时候才会进行。如果不创建一个 Table 对象,而且永远都不引用Table.b1 或
Table.b2,那么 static Bowl b1 和b2 永远都不会创建。然而,只有在创建了第一个 Table 对象之后(或者
发生了第一次static 访问),它们才会创建。在那以后,static 对象不会重新初始化。
114
初始化的顺序是首先static(如果它们尚未由前一次对象创建过程初始化),接着是非static 对象。大家
可从输出结果中找到相应的证据。
在这里有必要总结一下对象的创建过程。请考虑一个名为 Dog 的类:
(1) 类型为 Dog 的一个对象首次创建时,或者 Dog 类的static 方法/static 字段首次访问时,Java 解释器
必须找到Dog.class(在事先设好的类路径里搜索)。
(2) 找到Dog.class 后(它会创建一个 Class 对象,这将在后面学到),它的所有 static 初始化模块都会运
行。因此,static 初始化仅发生一次——在 Class 对象首次载入的时候。
(3) 创建一个new Dog()时,Dog 对象的构建进程首先会在内存堆(Heap)里为一个 Dog 对象分配足够多的存
储空间。
(4) 这种存储空间会清为零,将Dog 中的所有基本类型设为它们的默认值(零用于数字,以及 boolean 和
char 的等价设定)。
(5) 进行字段定义时发生的所有初始化都会执行。
(6) 执行构建器。正如第6 章将要讲到的那样,这实际可能要求进行相当多的操作,特别是在涉及继承的时
候