Java提升篇——靜態代碼塊、構造代碼塊、構造函數以及Java類初始化順序

靜態代碼塊:用staitc聲明,jvm加載類時執行,僅執行一次
構造代碼塊:類中直接用{}定義,每一次建立對象時執行。
執行順序優先級:靜態塊,main(),構造塊,構造方法。java

構造函數

public HelloA(){//構造函數
    }

關於構造函數,如下幾點要注意:
1.對象一創建,就會調用與之相應的構造函數,也就是說,不創建對象,構造函數時不會運行的。
2.構造函數的做用是用於給對象進行初始化。
3.一個對象創建,構造函數只運行一次,而通常方法能夠被該對象調用屢次。segmentfault

構造代碼塊

{//構造代碼塊    
}

關於構造代碼塊,如下幾點要注意:jvm

  1. 構造代碼塊的做用是給對象進行初始化。
  2. 對象一創建就運行構造代碼塊了,並且優先於構造函數執行。這裏要強調一下,有對象創建,纔會運行構造代碼塊,類不能調用構造代碼塊的,並且構造代碼塊與構造函數的執行順序是前者先於後者執行
  3. 構造代碼塊與構造函數的區別是:構造代碼塊是給全部對象進行統一初始化,而構造函數是給對應的對象初始化,由於構造函數是能夠多個的,運行哪一個構造函數就會創建什麼樣的對象,但不管創建哪一個對象,都會先執行相同的構造代碼塊。也就是說,構造代碼塊中定義的是不一樣對象共性的初始化內容。

靜態代碼塊

static {//靜態代碼塊    
}

關於靜態代碼塊,要注意的是:函數

  1. 它是隨着類的加載而執行,只執行一次,並優先於主函數。具體說,靜態代碼塊是由類調用的。類調用時,先執行靜態代碼塊,而後才執行主函數的。
  2. 靜態代碼塊其實就是給類初始化的,而構造代碼塊是給對象初始化的
  3. 靜態代碼塊中的變量是局部變量,與普通函數中的局部變量性質沒有區別。
  4. 一個類中能夠有多個靜態代碼塊
public class Test{
staitc int cnt=6;
static{
      cnt+=9;
}
public static void main(String[] args) {
      System.out.println(cnt);
}
static{
      cnt/=3;
}
}
運行結果:
5

Java類初始化順序

## 對於一個類的狀況

例子1:post

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:spa

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:3d

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的構造函數

對於一個類而言,按照以下順序執行:code

  1. 執行靜態代碼塊
  2. 執行構造代碼塊
  3. 執行構造函數

對於靜態變量、靜態初始化塊、變量、初始化塊、構造器,它們的初始化順序依次是(靜態變量、靜態初始化塊)>(變量、初始化塊)>構造器。對象

例子4:blog

 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 }

運行以上代碼,咱們會獲得以下的輸出結果:

  1. 靜態變量

  2. 靜態初始化塊

  3. 變量

  4. 初始化塊

  5. 構造器

## 對於繼承狀況

例子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的構造函數

當涉及到繼承時,按照以下順序執行:

  1. 執行父類的靜態代碼塊,並初始化父類靜態成員變量
  2. 執行子類的靜態代碼塊,並初始化子類靜態成員變量
  3. 執行父類的構造代碼塊,執行父類的構造函數,並初始化父類普通成員變量
  4. 執行子類的構造代碼塊, 執行子類的構造函數,並初始化子類普通成員變量
Java初始化順序如圖:

 

例子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類初始化順序

相關文章
相關標籤/搜索