本题出自《Think in Java》第5章,主要考验对类初始化的理解,轻微烧脑,挑战一下吧~
class Bowl {
Bowl(int marker) {
System.out.println("Bowl(" + marker + ")");
}
void f1(int marker) {
System.out.println("f1(" + marker + ")");
}
}
class Table {
Bowl bowl1 = new Bowl(1);
Table() {
System.out.println("Table()");
bowl2.f1(2);
}
void f2(int marker) {
System.out.println("f2(" + marker + ")");
}
static Bowl bowl6;
static Bowl bowl2 = new Bowl(2);
static void fs(int marker) {
System.out.println("fs(" + marker + ")");
}
static {
bowl6 = new Bowl(6);
}
static Bowl bowl7 = new Bowl(7);
}
class Cupboard {
Bowl bowl3 = new Bowl(3);
static Bowl bowl4 = new Bowl(4);
public Cupboard() {
System.out.println("Cupboard()");
bowl4.f1(4);
}
void f3(int marker) {
System.out.println("f3(" + marker + ")");
}
static Bowl bowl5 = new Bowl(5);
}
public class ClassInitialization {
public static void main(String[] args) {
System.out.println("now in main");
Table.fs(0);
System.out.println("Creating new Cupboard in main");
new Cupboard();
System.out.println("Creating new Table in main");
Table table = new Table();
table.f2(1);
cupboard.f3(1);
}
static Cupboard cupboard = new Cupboard();
}
(答案在最后,先别着急看,做完再对答案才有意思)
如果没有思路的话,可以参考几个要点:
1. 类在加载的时候就会初始化静态变量和静态代码块,静态变量和静态代码块可以看做是类加载过程的一部分,执行一次就够了;
2. 静态方法的执行通常不会引发类的实例化;
3. 在实例化对象的时候,变量的初始化先于构造函数,变量定义的先后顺序决定了初始化的顺序。
具体到这个例子:
1. 执行main方法的时候,会加载ClassInitialization
这个类,因此就会导致静态变量的初始化,即cupboard
对象的创建;
2. 创建cupboard
对象时,首先加载类,初始化静态变量和静态代码块,然后因为是实例化,所以会初始化该实例的属性,然后是构造函数;
3. 之后进入main
方法,执行Table
的静态方法会先进行类加载,此时会初始化静态变量和静态代码块,顺序为定义的顺序,由于没有进行实例化,不会初始化普通变量和执行构造函数;
4. 在new Cupboard()
时,由于类已经完成加载,静态变量和静态代码块就不需要再次执行了,直接创建Cupboard
对象即可。
好了,说了这么多,对对答案:
Bowl(4)
Bowl(5)
Bowl(3)
Cupboard()
f1(4)
now in main
Bowl(2)
Bowl(6)
Bowl(7)
fs(0)
Creating new Cupboard in main
Bowl(3)
Cupboard()
f1(4)
Creating new Table in main
Bowl(1)
Table()
f1(2)
f2(1)
f3(1)