域初始化、靜態塊及構造方法等在建立類例項時的執行順序 (轉)
在《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/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Java中構造方法,構造程式碼塊和靜態程式碼塊執行順序詳解Java構造方法
- Java普通程式碼塊,構造程式碼塊,靜態程式碼塊區別,執行順序的程式碼例項Java
- c#通過反射動態執行類的例項及靜態方法C#反射
- 子類繼承父類(父類和子類裡:塊、靜態塊、構造和方法覆寫)之間呼叫順序繼承
- Java中建構函式、靜態程式碼塊、程式碼塊的執行順序Java函式
- 總結類初始化時的程式碼執行順序
- Java初始化靜態變數的時間順序Java變數
- 深入理解Java中靜態初始化塊、初始化塊和構造方法Java構造方法
- 靜態程式碼塊、構造程式碼塊、構造方法構造方法
- static程式碼塊、構造程式碼塊、建構函式以及Java類初始化順序C程式函式Java
- 建立派生類物件,建構函式的執行順序物件函式
- java中靜態初始化塊,例項初始化塊,建構函式區別Java函式
- Java子類和父類的初始化執行順序Java
- Python例項方法、類方法、靜態方法Python
- 附例項!圖解React的生命週期及執行順序圖解React
- Python Class 的例項方法/類方法/靜態方法Python
- C#類中方法的執行順序C#
- Java的類的例項化順序Java
- 類的例項化順序和分析
- 靜態程式碼塊類載入時並不會執行
- Java類的基本執行順序Java
- 在繼承當中這些方法及程式碼塊執行順序是什麼樣的繼承
- Javascript在頁面載入時的執行順序JavaScript
- java類初始化的順序Java
- 靜態順序表和動態順序表 對比
- Java 類初始化順序Java
- Java類初始化順序Java
- Jmeter的元件作用域和執行順序JMeter元件
- javascript 靜態方法和例項方法例項JavaScript
- Jmeter元件執行順序與作用域JMeter元件
- 基礎才是重中之重~泛型類的靜態構造方法可不是隻執行一次呀泛型構造方法
- CMake和靜態庫順序
- js--Object的靜態方法和例項方法JSObject
- Python - 物件導向程式設計 - 例項方法、靜態方法、類方法Python物件程式設計
- C++ 結構體例項和類例項的初始化C++結構體
- Java中,類與類,類中的程式碼執行順序Java
- Effective Java - 靜態方法與構造器Java
- Java類(繼承)初始化順序Java繼承