“5.7.2 静态数据的初始化”这一小节介绍了类中静态数据成员的初始化方法。众所周知,无论创建多少对象,静态数据都只占用一份存储区域。static关键字不能应用于局部变量,它只能作用于域,比如类、数据成员和行为方法。如果一个域是静态的基本类型域,且也没有对它进行初始化,那么它就会获得基本类型的标准初值;如果它是一个对象引用,那么它的默认初始化值就是null。
如果想在定义处进行初始化,采取的方法跟非静态数据没什么不同,下面看一个例子:
importstaticnet.mindview.util.Print.*; classBowl { Bowl(intmarker) { print("Bowl("+marker+")"); } voidf1(intmarker) { print("f1("+marker+")"); } } classTable { staticBowlbowl1=newBowl(1); Table() { print("Table()"); bowl2.f1(1); } voidf2(intmarker) { print("f2("+marker+")"); } staticBowlbowl2=newBowl(2); } classCupboard { Bowlbowl3=newBowl(3); staticBowlbowl4=newBowl(4); Cupboard() { print("Cupboard()"); bowl4.f1(2); } voidf3(intmarker) { print("f3("+marker+")"); } staticBowlbowl5=newBowl(5); } publicclassStaticInitialization { publicstaticvoidmain(String[] args) { print("Creating new Cupboard() in main"); newCupboard(); print("Creating new Cupboard() in main"); newCupboard(); table.f2(1); cupboard.f3(1); } staticTabletable=newTable(); staticCupboardcupboard=newCupboard(); }
/* Output:
Bowl(1)
Bowl(2)
Table()
f1(1)
Bowl(4)
Bowl(5)
Bowl(3)
Cupboard()
f1(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f1(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f1(2)
f2(1)
f3(1)
*///:~
由输出可见,静态初始化只有在必要时刻才会进行。如果不创建Table对象,也不引用Table.b1或Table.b2,那么敬爱的Bowl b1和b2永远都不会被创建。只有在第一个Table对象被创建(或者第一次访问静态数据)的时候,他们才会被初始化。此后,静态对象不会再次被初始化,即只初始化一次。初始化的顺序是先静态对象,而后是非静态对象。
Java允许将多个静态初始化动作组织成一个特殊的“静态子句”(有时也叫做“静态块”)。就像下面这样:
publicclassSpoon { staticinti; static { i=47; } }
尽管上面的代码看起来像个方法,但它实际只是一段跟在static关键字后面的代码。与其他静态初始化动作一样,这段代码仅执行一次:当首次生成这个类的对象或首次访问属于那个类的静态域时。例如:
importstaticnet.mindview.util.Print.*; classCup { Cup(intmarker) { print("Cup("+marker+")"); } voidf(intmarker) { print("f("+marker+")"); } } classCups { staticCupcup1; staticCupcup2; static { cup1=newCup(1); cup2=newCup(2); } Cups() { print("Cups()"); } } publicclassExplicitStatic { publicstaticvoidmain(String[] args) { print("Inside main()"); Cups.cup1.f(99); // (1) } // static Cups cups1 = new Cups(); // (2) // static Cups cups2 = new Cups(); // (2) }
/* Output:
Inside main()
Cup(1)
Cup(2)
f(99)
*///:~
标为(1)和(2)中无论哪一行被运行,Cups的静态初始化动作都会得到执行。此外,不管运行几行,静态初始化动作只会运行一次,可以通过运行代码看到这种现象。
“5.7.2 非静态实例初始化”中提到了一种用来初始化每一个对象的非静态变量方法,该方法一般使用的不多,跟静态变量初始化唯一的区别就是省略了static关键词,但是初始化原理截然不同,即对象每次被实例化都会执行一次,而静态变量只会执行一次。例如:
importstaticnet.mindview.util.Print.*; classMug { Mug(intmarker) { print("Mug("+marker+")"); } voidf(intmarker) { print("f("+marker+")"); } } publicclassMugs { Mugmug1; Mugmug2; { mug1=newMug(1); mug2=newMug(2); print("mug1 & mug2 initialized"); } Mugs() { print("Mugs()"); } Mugs(inti) { print("Mugs(int)"); } publicstaticvoidmain(String[] args) { print("Inside main()"); newMugs(); print("new Mugs() completed"); newMugs(1); print("new Mugs(1) completed"); } }
/* Output:
Inside main()
Mug(1)
Mug(2)
mug1 & mug2 initialized
Mugs()
new Mugs() completed
Mug(1)
Mug(2)
mug1 & mug2 initialized
Mugs(int)
new Mugs(1) completed
*///:~
从输出可以看到实例初始化子句是在两个构造器之前执行的。