標籤:完全 title comm 靜態成員 說明 function ring inf 構造器
- 類的三大成員:成員變數、構造方法、方法,初始化代碼塊是類的第4個成員
- 初始化塊用於對類或者對象的初始化,
- 一個類的初始化塊可以有0~多個,按先後順序執行
- 跟執行個體方法-->類方法、執行個體變數-->類變數一樣,也可以用static修飾初始化塊,靜態初始化塊-->非靜態初始化塊
- 初始化塊總是先於構造器執行
- 非靜態初始化塊
- 非靜態初始化塊相當於是對構造器的補充,用於建立對象時給對象的初始化,在構造器之前執行
- 如果一段初始化代碼對所有構造器完全相同,且無需接收參數,那就可以將其提取到非靜態初始化代碼塊中
- 在繼承中,先後執行父類A的非靜態塊、構造器,再執行父類B的非靜態塊、構造器,最後才執行子類的非靜態塊、構造器
- 實際上,經過編譯後,非靜態塊已經添加到構造器中,且位於所有構造器代碼的前面
- 靜態初始化塊下面通過一段代碼,看看繼承中的靜態塊、非靜態塊、構造方法的執行順序
- 靜態初始化塊用static修飾,又叫類初始化塊
- 非靜態塊負責對對象執行初始化,而類初始化塊負責對類進行初始化,因此類初始化塊是在類初始化階段就執行
- 靜態塊跟靜態方法一樣,不能訪問非靜態成員
- 在繼承中,先後執行父類A的靜態塊,父類B的靜態塊,最後子類的靜態塊,然後再執行父類A的非靜態塊和構造器,然後是B類,最後執行子類的非靜態塊和構造器
- 因為靜態塊是在類的初始化階段完成的,因此在建立某個類的第二個對象時,該類的靜態塊就不會執行了
public class Test{ public static void main(String[] args) { C c1=new C(); System.out.println("--------下面第二次建立C類對象---------"); C c2=new C(); }}class C extends B{ static { System.out.println("C的靜態代碼塊"); } { System.out.println("C的非靜態代碼塊"); } C(){ System.out.println("C的無參構造方法"); } C(String str){ System.out.println("C的有參構造方法"); }}class B extends A{ static { System.out.println("B的靜態代碼塊"); } { System.out.println("B的非靜態代碼塊"); } B(){ System.out.println("B的無參構造方法"); } B(String str){ System.out.println("B的有參構造方法"); }}class A{ static { System.out.println("A的靜態代碼塊"); } { System.out.println("A的非靜態代碼塊"); } A(){ System.out.println("A的無參構造方法"); } A(String str){ System.out.println("A的有參構造方法"); }}
輸出為:
A的靜態代碼塊
B的靜態代碼塊
C的靜態代碼塊
A的非靜態代碼塊
A的無參構造方法
B的非靜態代碼塊
B的無參構造方法
C的非靜態代碼塊
C的無參構造方法
--------下面第二次建立C類對象---------
A的非靜態代碼塊
A的無參構造方法
B的非靜態代碼塊
B的無參構造方法
C的非靜態代碼塊
C的無參構造方法
靜態初始化塊與靜態成員變數的執行順序
- JVM第一次使用某個類時,在準備階段給所有靜態成員分配記憶體,在初始化階段初始化這些靜態成員變數,就是執行初始化代碼或者聲明成員變數時指定的初始值,執行順序與原始碼中的順序相同
- 按原始碼中的先後順序執行,見範例程式碼:
public class Test{ public static void main(String[] args) { A a=new A(); System.out.println(a.num); //輸出10,而不是6,說明先執行聲明賦值6,然後才執行靜態塊賦值10 }}class A{ public static int num=6; static{ num=10; }}
Java代碼塊