Chapter5_初始化与清理_构造器初始化
一、构造器初始化的基本顺序
在使用构造器进行初始化时,最需要注意的是初始化的顺序,这种方法可以给初始化的顺序带来很大的灵活性。看如下的一个例子。
1 class Window{ 2 Window(int marker){ 3 System.out.println("Window(" + marker + ")"); 4 } 5 } 6 7 class House{ 8 Window w1 = new Window(1); 9 House(){ 10 System.out.println("House()"); 11 w3 = new Window(33); 12 } 13 Window w2 = new Window(2); 14 void f(){ 15 System.out.println("f()"); 16 } 17 Window w3 = new Window(3); 18 } 19 20 public class test{ 21 public static void main(String args[]){ 22 House h = new House(); 23 h.f(); 24 } 25 }
1 Window(1) 2 Window(2) 3 Window(3) 4 House() 5 Window(33) 6 f()
从输出中我们可以看出来,初始化的顺序有两点最基本的需要注意:
(1)成员初始化是默认第一个进行的,由编译器控制执行,发生在调用这个类构造器之前,不能阻止其发生。
(2)变量定义的先后顺序决定了初始化的顺序,即使这些变量定义散布在方法定义之间,变量的初始化仍会在任何方法被调用之前执行。
二、静态数据的初始化
先看一个例子。
1 class Bowl{ 2 Bowl(int marker){ 3 System.out.println("Bowl(" + marker + ")"); 4 } 5 void f1(int marker){ 6 System.out.println("f1(" + marker + ")"); 7 } 8 } 9 10 class Table{ 11 static Bowl bowl1 = new Bowl(1); 12 Table(){ 13 System.out.println("Table()"); 14 bowl2.f1(1); 15 } 16 void f2(int marker){ 17 System.out.println("f2(" + marker + ")"); 18 } 19 static Bowl bowl2 = new Bowl(2); 20 } 21 22 class Cupboard{ 23 Bowl bowl3 = new Bowl(3); 24 static Bowl bowl4 = new Bowl(4); 25 Cupboard(){ 26 System.out.println("Cupborad()"); 27 bowl4.f1(2); 28 } 29 void f3(int marker){ 30 System.out.println("f3(" + marker + ")"); 31 } 32 static Bowl bowl5 = new Bowl(5); 33 } 34 35 public class test{ 36 public static void main(String args[]){ 37 System.out.println("creating new cupboard() in main"); 38 new Cupboard(); 39 System.out.println("creating new cupboard() in main"); 40 new Cupboard(); 41 table.f2(1); 42 cupboard.f3(1); 43 } 44 static Table table = new Table(); 45 static Cupboard cupboard = new Cupboard(); 46 }
Bowl(1) Bowl(2) Table() f1(1) Bowl(4) Bowl(5) Bowl(3) Cupborad() f1(2) creating new cupboard() in main Bowl(3) Cupborad() f1(2) creating new cupboard() in main Bowl(3) Cupborad() f1(2) f2(1) f3(1)
从输出可以看出来当有静态成员变量存在时,初始化的顺序是,先对静态的成员变量进行顺序初始化,再对非静态的成员变量进行顺序初始化,需要注意的是,由于静态变量是一块共享的内存区域,所以某个类的静态变量只会被初始化一次。
书上总结了创建一个对象的编译器的详细过程(假设类为dog):
(1)由于构造器是静态方法,当首次创建类型为Dog的对象时,或者首次访问静态域时,java解释器首先会查找类路径,定位dog.class文件。
(2)首次加载dog.class,然后执行一次静态初始化的动作。
(3)用new dog()创建对象时,先在堆上给dog分配足够的内存空间。
(4)将这块存储空间清零,会将dog中的所有成员变量变为默认值。
(5)执行出现于字段定义处的初始化动作。
(6)执行构造器。