域初始化、靜態塊及構造方法等在建立類例項時的執行順序 (轉)

amyz發表於2007-11-25
域初始化、靜態塊及構造方法等在建立類例項時的執行順序 (轉)[@more@]

在《Core 2: volumn 1, Edition 5》一書的第四章“與類”中講到域賦值語句、例項塊、靜態塊及構造方法等在建立類例項時的順序,中文譯本有些處翻譯的不貼切,而英文原書中也有一處錯誤。本文透過一個小來說明類例項構造過程中的語句執行順序。

程式如下

public class Teststaticblock
{
 public Teststaticblock()
 {
 this("second");
 System.out.println("begin constructor");
 System.out.println(s_a);
 System.out.println(s_b);
 System.out.println(c);
 System.out.println(d);
// this("second");//call to this must be first statement in constructor
 s_a=1111;
 s_b=2222;
 c=3333;
 d=4444;
 System.out.println(s_a);
 System.out.println(s_b);
 System.out.println(c);
 System.out.println(d);
 System.out.println("end constructor");
 }
 public Teststaticblock(String s)
 {
 System.out.println("begin second constructor");
 System.out.println("end second constructor");
 }
 public static void main(String args[])
 {
 System.out.println("begin main");
 System.out.println(s_a);
 System.out.println(s_b);
// System.out.println(c);//non-static variable c cannot be referenced from a static context
// System.out.println(d);//non-static variable c cannot be referenced from a static context
 s_a=11111;
 s_b=22222;
// c=33333;//non-static variable c cannot be referenced from a static context
// d=44444;//non-static variable c cannot be referenced from a static context
 System.out.println(s_a);
 System.out.println(s_b);
// System.out.println(c);//non-static variable c cannot be referenced from a static context
// System.out.println(d);//non-static variable c cannot be referenced from a static context
 System.out.println("before new class ");
 Teststaticblock t = new Teststaticblock();
 System.out.println("end new class object");
 System.out.println(s_a);
 System.out.println(s_b);
// System.out.println(c);//non-static variable c cannot be referenced from a static context
// System.out.println(d);//non-static variable c cannot be referenced from a static context
 s_a=111111;
 s_b=222222;
// c=333333;//non-static variable c cannot be referenced from a static context
// d=444444;//non-static variable c cannot be referenced from a static context
 System.out.println(s_a);
 System.out.println(s_b);
// System.out.println(c);//non-static variable c cannot be referenced from a static context
// System.out.println(d);//non-static variable c cannot be referenced from a static context
 System.out.println("end main");
 }
 
 static int s_a=1;
 int c=3;
 {
 System.out.println("begin block");
 System.out.println(s_a);
 System.out.println(s_b);
 System.out.println(c);
// System.out.println(d);//illegal forward reference
 s_a=111;
 s_b=222;
 c=333;
 d=444;
 System.out.println(s_a);
 System.out.println(s_b);
 System.out.println(c);
// System.out.println(d);//illegal forward reference
 System.out.println("end block");
 }
 static
 {
 System.out.println("begin static block");
 System.out.println(s_a);
// System.out.println(s_b);//illegal forward reference
// System.out.println(c);//non-static variable c cannot be referenced from a static context
// System.out.println(d);//non-static variable c cannot be referenced from a static context
 s_a=11;
 s_b=22;
 System.out.println(s_a);
// System.out.println(s_b);//illegal forward reference
// System.out.println(c);//non-static variable c cannot be referenced from a static context
// System.out.println(d);//non-static variable c cannot be referenced from a static context
 System.out.println("end static block");
 }
 int d=4;
 static int s_b=2;
 
}

輸出如下:

begin static block
1
11
end static block
begin main
11
2
11111
22222
before new class object
begin block
11111
22222
3
111
222
333
end block
begin second constructor
end second constructor
begin constructor
111
222
333
4
1111
2222
3333
4444
end constructor
end new class object
1111
2222
111111
222222
end main

透過對輸出進行分析,可以得出如下結果:
1、在類第一次載入時候,會執行靜態域(field)初始化語句和靜態塊(用static{}包含的部分)。
這裡要注意:
  a、不管靜態域宣告語句的實際位置在哪兒,當第一次載入類的時候都會首先對它初始化為預設值(0,false,null等)。
  b、即使靜態域宣告中使用了顯式初始化語句(比如:int x=3),第一次載入類的時候也會先把它初始化為預設值(此時x為0),然後再按照下面說的要點c來執行賦值語句(x=3)。
  c、對於靜態域的顯式初始化語句和靜態塊,按照在類中程式碼出現的先後順序執行。
  因此,在上面的例子程式中,我們看到
   static int s_a=1;
   static
  {
  s_a=11;
  s_b=22;
  }
  static int s_b=2;
  對s_a,s_b會有不同的效果。類載入時候,s_a,s_b都被初始化為0,然後由於依照程式碼順序執行了s_a=1;s_a=11;s_b=22;s_b=2;結果s_a、s_b分別變成了11和2。

2、當構造類例項時候,會先對例項域初始化為預設值,然後執行例項塊(用{}括起來的部分),然後執行構造方法。其中:
  a、如同1中一樣,如果有例項域的顯式初始化語句,程式仍然是先將該域初始化為預設值,然後按照程式碼在類中出現的先後順序執行初始化語句或者例項塊。如果例項塊位置在初始化語句前面,即使它改變了該域的值,也會被隨後執行的初始化語句改回去。
  b、在進入構造方法後,如果構造方法第一句是使用this(...)另一構造方法的話,則先執行另一構造方法,然後再執行本構造方法的方法體。這種用法必須讓this(...)位於第一句。

《Core java 2》書中所說的"進入構造方法後,如果第一句是呼叫別的構造方法,則進入別的構造方法。否則,執行例項塊"的提法有問題。事實是,不管是否使用this()都會先執行例項塊,再進入構造方法。另外,本程式需要在sdk1.4下編譯,在sdk1.3下編譯將不允許在靜態塊或例項塊中改變位置在它們後面宣告的域的值。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752019/viewspace-984575/,如需轉載,請註明出處,否則將追究法律責任。

相關文章