在《thinking in java》里的4.4.2中,提到初始化的顺序:在一个类里,初始化的顺序是由变量在类内的定义顺序决定的。即使变量定义大量遍布于方法定义的中间,那些变量仍会在调用任何方法之前得到初始化——甚至在构建器调用之前。

 
  1. class Tag { 
  2.     Tag(int marker) { 
  3.         System.out.println("Tag(" + marker + ")"); 
  4.     } 
  5. class Card { 
  6.     Tag t1 = new Tag(1); // Before constructor 
  7.     Card() { 
  8.         // Indicate we're in the constructor: 
  9.         System.out.println("Card()"); 
  10.         t3 = new Tag(33); // Re-initialize t3 
  11.     } 
  12.     Tag t2 = new Tag(2); // After constructor 
  13.     void f() { 
  14.         System.out.println("f()"); 
  15.     } 
  16.     Tag t3 = new Tag(3); // At end 
  17. public class OrderOfInitialization { 
  18.     public static void main(String[] args) { 
  19.         Card t = new Card(); 
  20.         t.f(); // Shows that construction is done 
  21.     } 

 个人理解:先从入口方法main方法所在的类开始。首先创建Card型对象t,调用构造器Card()。但是在调用构造器之前,会先初始化Card对象所需要的属性:t1,t2,t3,虽然他们处于Card类的不同位置。当t1,t2,t3三个对象初始化完成后,才真正调用构造器Card()。在构造器里,t3又被初始化了一遍。t初始化完成后,进入下一条语句,调用t的方法f()。这样,系统输出的文本应该就是

 

  1. Tag(1
  2. Tag(2
  3. Tag(3
  4. Card() 
  5. Tag(33
  6. f() 

 然后,关于静态变量的初始化顺序,《Thinking in java》中说道:若数据是静态的(static),那么同样的事情就会发生;如果它属于一个基本类型(主类型),而且未对其初始化,就会自动获得自己的标准基本类型初始值;如果它是指向一个对象的句柄,那么除非新建一个对象,并将句柄同它连接起来,否则就会得到一个空值(NULL)。如果想在定义的同时进行初始化,采取的方法与非静态值表面看起来是相同的。但由于static 值只有一个存储区域,所以无论创建多少个对象,都必然会遇到何时对那个存储区域进行初始化的问题。下面这个例子可将这个问题说更清楚一些:

 

  1. class Bowl { 
  2.     Bowl(int marker) { 
  3.         System.out.println("Bowl(" + marker + ")"); 
  4.     } 
  5.     void f(int marker) { 
  6.         System.out.println("f(" + marker + ")"); 
  7.     } 
  8. class Table { 
  9.     static Bowl b1 = new Bowl(1); 
  10.     Table() { 
  11.         System.out.println("Table()"); 
  12.         b2.f(1); 
  13.     } 
  14.     void f2(int marker) { 
  15.         System.out.println("f2(" + marker + ")"); 
  16.     } 
  17.     static Bowl b2 = new Bowl(2); 
  18. class Cupboard { 
  19.     Bowl b3 = new Bowl(3); 
  20.     static Bowl b4 = new Bowl(4); 
  21.     Cupboard() { 
  22.         System.out.println("Cupboard()"); 
  23.     b4.f(2); 
  24.     } 
  25.     void f3(int marker) { 
  26.         System.out.println("f3(" + marker + ")"); 
  27.     } 
  28.     static Bowl b5 = new Bowl(5); 
  29. public class StaticInitialization { 
  30.     public static void main(String[] args) { 
  31.     System.out.println( 
  32.         "Creating new Cupboard() in main"); 
  33.         new Cupboard(); 
  34.         System.out.println( 
  35.         "Creating new Cupboard() in main"); 
  36.         new Cupboard(); 
  37.         t2.f2(1); 
  38.         t3.f3(1); 
  39.     } 
  40.     static Table t2 = new Table(); 
  41.     static Cupboard t3 = new Cupboard(); 

  同样,先从入口方法main方法所在的类开始。由于静态变量必须先构造(纯属个人理解),所以,Table型的对象t2是最新被构造的。调用构造器Table()。在Table类中,由于声明了静态变量b1与b2,所以先调用Bowl的构造器来创建初始化b1与b2。b1与b2初始化完成后,再调用Table的构造器。同时在Table的构造器中,通过b2调用方法f(),返回的是一个字符串。这样,t2构造完毕后,创建下一个静态变量,Cupboard类型的对象t3。同理,先调用t3的构造器Cupboard(),但是在Cupboard类中,有两个静态变量b4与b5,所以会先初始化b4与b5。但是,在调用构造器之前,还有一步,就是初始化Cupboard对象的属性,这里是一个Bowl型对象b3,所以b3会在调用Cupboard构造器之前被初始化。接着,调用构造器Cupboard用来初始化t3。在构造器中,通过b4调用了方法f(),结果也是输出一串字符串。在t3被初始化完成后,main方法所在的类的所有静态变量都被初始化了,接下来进入main方法。首先是输出一条字符串,然后是创建一个Cupboard对象。这样又要调用Cupboard的构造器。但是由于之前已经初始化了Cupboard类的静态变量b4与b5,所以不会再初始化。但是由于b3属于Cupboard对象的一个属性,所以,要先初始化b3,然后再调用构造器Cupboard()。下两条语句同样执行上述操作。最后通过t2调用方法f2,t3调用方法f3,这样所有的初始化工作就结束了。输出的结果应该是:

 

  1. Bowl(1
  2. Bowl(2
  3. Table() 
  4. f(1
  5. Bowl(4
  6. Bowl(5
  7. Bowl(3
  8. Cupboard() 
  9. f(2
  10. Creating new Cupboard() in main 
  11. Bowl(3
  12. Cupboard() 
  13. f(2
  14. Creating new Cupboard() in main 
  15. Bowl(3
  16. Cupboard() 
  17. f(2
  18. f2(1
  19. f3(1

  总结:要初始化一个对象,编译器首先会找到找到这个对象相应的类,然后首先初始化相应类中的static对象,接来下才是初始化非static对象(作为对象的属性的变量),在接下来才是调用构造器。

  总结如果有错误,欢迎大家指出。