靜態代碼塊:用staitc聲明,jvm加載類時執行,僅執行一次
構造代碼塊:類中直接用{}定義,每一次創建對象時執行。
執行順序優先級:靜態塊,main(),構造塊,構造方法。
public HelloA(){//構造函數 }
關於構造函數,以下幾點要注意:
1.對象一建立,就會調用與之相應的構造函數,也就是說,不建立對象,構造函數時不會運行的。
2.構造函數的作用是用於給對象進行初始化。
3.一個對象建立,構造函數只運行一次,而一般方法可以被該對象調用多次。
{//構造代碼塊 }
關於構造代碼塊,以下幾點要注意:
static {//靜態代碼塊 }
關於靜態代碼塊,要注意的是:
public class Test{ staitc int cnt=6; static{ cnt+=9; } public static void main(String[] args) { System.out.println(cnt); } static{ cnt/=3; } } 運行結果: 5
例子1:
public class HelloA { public HelloA(){//構造函數 System.out.println("A的構造函數"); } {//構造代碼塊 System.out.println("A的構造代碼塊"); } static {//靜態代碼塊 System.out.println("A的靜態代碼塊"); } public static void main(String[] args) { } } 運行結果: A的靜態代碼塊
例子2:
public class HelloA { public HelloA(){//構造函數 System.out.println("A的構造函數"); } {//構造代碼塊 System.out.println("A的構造代碼塊"); } static {//靜態代碼塊 System.out.println("A的靜態代碼塊"); } public static void main(String[] args) { HelloA a=new HelloA(); } } 運行結果: A的靜態代碼塊 A的構造代碼塊 A的構造函數
例子3:
public class HelloA { public HelloA(){//構造函數 System.out.println("A的構造函數"); } {//構造代碼塊 System.out.println("A的構造代碼塊"); } static {//靜態代碼塊 System.out.println("A的靜態代碼塊"); } public static void main(String[] args) { HelloA a=new HelloA(); HelloA b=new HelloA(); } } 運行結果: A的靜態代碼塊 A的構造代碼塊 A的構造函數 A的構造代碼塊 A的構造函數
對於一個類而言,按照如下順序執行:
對於靜態變量、靜態初始化塊、變量、初始化塊、構造器,它們的初始化順序依次是(靜態變量、靜態初始化塊)>(變量、初始化塊)>構造器。
例子4:
1 public class InitialOrderTest { 2 /* 靜態變量 */ 3 public static String staticField = "靜態變量"; 4 /* 變量 */ 5 public String field = "變量"; 6 /* 靜態初始化塊 */ 7 static { 8 System.out.println( staticField ); 9 System.out.println( "靜態初始化塊" ); 10 } 11 /* 初始化塊 */ 12 { 13 System.out.println( field ); 14 System.out.println( "初始化塊" ); 15 } 16 /* 構造器 */ 17 public InitialOrderTest() 18 { 19 System.out.println( "構造器" ); 20 } 21 22 23 public static void main( String[] args ) 24 { 25 new InitialOrderTest(); 26 } 27 }
運行以上代碼,我們會得到如下的輸出結果:
例子5:
public class HelloA { public HelloA(){//構造函數 System.out.println("A的構造函數"); } {//構造代碼塊 System.out.println("A的構造代碼塊"); } static {//靜態代碼塊 System.out.println("A的靜態代碼塊"); } } public class HelloB extends HelloA{ public HelloB(){//構造函數 System.out.println("B的構造函數"); } {//構造代碼塊 System.out.println("B的構造代碼塊"); } static {//靜態代碼塊 System.out.println("B的靜態代碼塊"); } public static void main(String[] args) { HelloB b=new HelloB(); } } 運行結果: A的靜態代碼塊 B的靜態代碼塊 A的構造代碼塊 A的構造函數 B的構造代碼塊 B的構造函數
當涉及到繼承時,按照如下順序執行:
例子6:
1 class Parent { 2 /* 靜態變量 */ 3 public static String p_StaticField = "父類--靜態變量"; 4 /* 變量 */ 5 public String p_Field = "父類--變量"; 6 protected int i = 9; 7 protected int j = 0; 8 /* 靜態初始化塊 */ 9 static { 10 System.out.println( p_StaticField ); 11 System.out.println( "父類--靜態初始化塊" ); 12 } 13 /* 初始化塊 */ 14 { 15 System.out.println( p_Field ); 16 System.out.println( "父類--初始化塊" ); 17 } 18 /* 構造器 */ 19 public Parent() 20 { 21 System.out.println( "父類--構造器" ); 22 System.out.println( "i=" + i + ", j=" + j ); 23 j = 20; 24 } 25 } 26 27 public class SubClass extends Parent { 28 /* 靜態變量 */ 29 public static String s_StaticField = "子類--靜態變量"; 30 /* 變量 */ 31 public String s_Field = "子類--變量"; 32 /* 靜態初始化塊 */ 33 static { 34 System.out.println( s_StaticField ); 35 System.out.println( "子類--靜態初始化塊" ); 36 } 37 /* 初始化塊 */ 38 { 39 System.out.println( s_Field ); 40 System.out.println( "子類--初始化塊" ); 41 } 42 /* 構造器 */ 43 public SubClass() 44 { 45 System.out.println( "子類--構造器" ); 46 System.out.println( "i=" + i + ",j=" + j ); 47 } 48 49 50 /* 程序入口 */ 51 public static void main( String[] args ) 52 { 53 System.out.println( "子類main方法" ); 54 new SubClass(); 55 } 56 }
結果:
父類--靜態變量
父類--靜態初始化塊
子類--靜態變量
子類--靜態初始化塊
子類main方法
父類--變量
父類--初始化塊
父類--構造器
i=9, j=0
子類--變量
子類--初始化塊
子類--構造器
i=9,j=20
子類的靜態變量和靜態初始化塊的初始化是在父類的變量、初始化塊和構造器初始化之前就完成了。靜態變量、靜態初始化塊,變量、初始化塊初始化了順序取決於它們在類中出現的先後順序。
(1)訪問SubClass.main(),(這是一個static方法),於是裝載器就會為你尋找已經編譯的SubClass類的代碼(也就是SubClass.class文件)。在裝載的過程中,裝載器注意到它有一個基類(也就是extends所要表示的意思),於是它再裝載基類。不管你創不創建基類對象,這個過程總會發生。如果基類還有基類,那麼第二個基類也會被裝載,依此類推。
(2)執行根基類的static初始化,然後是下一個派生類的static初始化,依此類推。這個順序非常重要,因為派生類的“static初始化”有可能要依賴基類成員的正確初始化。
(3)當所有必要的類都已經裝載結束,開始執行main()方法體,並用new SubClass()創建對象。
(4)類SubClass存在父類,則調用父類的構造函數,你可以使用super來指定調用哪個構造函數。基類的構造過程以及構造順序,同派生類的相同。首先基類中各個變量按照字面順序進行初始化,然後執行基類的構造函數的其余部分。
(5)對子類成員數據按照它們聲明的順序初始化,執行子類構造函數的其余部分。
參考文章鏈接:
java-靜態代碼塊,構造代碼塊,構造函數
Java類初始化順序