static

 在類的內部,變量定義的先後順序決定了初始化的順序。即變量定義散佈於方法定義之間,他們仍舊會在任何方法(包括構造器)被調用之前得到初始化。


static 修飾的是屬於類的,只有一份被對象所共有


************************************************************

************************************************************

參考:java類初始化順序

    我們大家都知道,對於靜態變量、靜態初始化塊、變量、初始化塊、構造器,它們的初始化順序依次是(靜態變量、靜態初始化塊)>(變量、初始化塊)>構造器。我們也可以通過下面的測試代碼來驗證這一點:

  1. public class InitialOrderTest {   
  2.   
  3.     // 靜態變量   
  4.     public static String staticField "靜態變量";   
  5.     // 變量   
  6.     public String field "變量";   
  7.   
  8.     // 靜態初始化塊   
  9.     static {   
  10.         System.out.println(staticField);   
  11.         System.out.println("靜態初始化塊");   
  12.     }   
  13.   
  14.     // 初始化塊   
  15.     {   
  16.         System.out.println(field);   
  17.         System.out.println("初始化塊");   
  18.     }   
  19.   
  20.     // 構造器   
  21.     public InitialOrderTest() {   
  22.         System.out.println("構造器");   
  23.     }   
  24.   
  25.     public static void main(String[] args) {   
  26.         new InitialOrderTest();   
  27.     }   
  28.  

運行以上代碼,我們會得到如下的輸出結果: 

  1. 靜態變量
  2. 靜態初始化塊
  3. 變量
  4. 初始化塊
  5. 構造器

 

*******************************************************

*******************************************************

思考:改變構造器 初始化塊 靜態初始化塊順序

  1. public class InitialOrderTest {   
  2.   
  3.     // 靜態變量   
  4.     public static String staticField "靜態變量";   
  5.     // 變量   
  6.     public String field "變量";   
  7.   
  8.     // 構造器
  9.     public InitialOrderTest() {
  10.         System.out.println("構造器");
  11.     }
  12.     // 初始化塊
  13.     {
  14.         System.out.println(field);
  15.         System.out.println("初始化塊");
  16.     }
  17.     // 靜態初始化塊   
  18.     static {   
  19.         System.out.println(staticField);   
  20.         System.out.println("靜態初始化塊");   
  21.       
  22.   
  23.     public static void main(String[] args) {   
  24.         new InitialOrderTest();   
  25.     }   
  26.  

**************************

output:

靜態變量
靜態初始化塊
變量
初始化塊
構造器

***************************

結論:代碼順序的改變不會改變輸出的順序。

 

*******************************************************

*******************************************************

思考二:在初始化塊添加輸出靜態變量語句。

  1. public class InitialOrderTest {   
  2.   
  3.     // 靜態變量   
  4.     public static String staticField "靜態變量";   
  5.     // 變量   
  6.     public String field "變量";   
  7.   
  8.     // 靜態初始化塊   
  9.     static {   
  10.         System.out.println(staticField);   
  11.         System.out.println("靜態初始化塊");   
  12.     }   
  13.   
  14.     // 初始化塊   
  15.     {   
  16.        System.out.println(field);   
  17.         System.out.println("初始化塊");   
  18.        System.out.println(staticField);
  19.     }   
  20.   
  21.     // 構造器   
  22.     public InitialOrderTest() {   
  23.         System.out.println("構造器");   
  24.     }   
  25.   
  26.     public static void main(String[] args) {   
  27.         new InitialOrderTest();   
  28.     }   
  29.  

******************************

output:

靜態初始化塊
變量
初始化塊
靜態變量
構造器

******************************

疑問:輸出變了。靜態變量只輸出一次,且是初始化塊中輸出。

 

*******************************************************

*******************************************************

這與上文中說的完全符合。那麼對於繼承情況下又會怎樣呢?我們仍然以一段測試代碼來獲取最終結果:

  1. class Parent {   
  2.     // 靜態變量   
  3.     public static String p_StaticField "父類--靜態變量";   
  4.     // 變量   
  5.     public String p_Field "父類--變量";   
  6.   
  7.     // 靜態初始化塊   
  8.     static {   
  9.         System.out.println(p_StaticField);   
  10.         System.out.println("父類--靜態初始化塊");   
  11.     }   
  12.   
  13.     // 初始化塊   
  14.     {   
  15.         System.out.println(p_Field);   
  16.         System.out.println("父類--初始化塊");   
  17.     }   
  18.   
  19.     // 構造器   
  20.     public Parent() {   
  21.         System.out.println("父類--構造器");   
  22.     }   
  23. }   
  24.   
  25. public class SubClass extends Parent {   
  26.     // 靜態變量   
  27.     public static String s_StaticField "子類--靜態變量";   
  28.     // 變量   
  29.     public String s_Field "子類--變量";   
  30.     // 靜態初始化塊   
  31.     static {   
  32.         System.out.println(s_StaticField);   
  33.         System.out.println("子類--靜態初始化塊");   
  34.     }   
  35.     // 初始化塊   
  36.     {   
  37.         System.out.println(s_Field);   
  38.         System.out.println("子類--初始化塊");   
  39.     }   
  40.   
  41.     // 構造器   
  42.     public SubClass() {   
  43.         System.out.println("子類--構造器");   
  44.     }   
  45.   
  46.     // 程序入口   
  47.     public static void main(String[] args) {   
  48.         new SubClass();   
  49.     }   
  50.  

 

運行一下上面的代碼,結果馬上呈現在我們的眼前: 

  1. 父類--靜態變量
  2. 父類--靜態初始化塊
  3. 子類--靜態變量
  4. 子類--靜態初始化塊
  5. 父類--變量
  6. 父類--初始化塊
  7. 父類--構造器
  8. 子類--變量
  9. 子類--初始化塊
  10. 子類--構造器

    現在,結果已經不言自明瞭。大家可能會注意到一點,那就是,並不是父類完全初始化完畢後才進行子類的初始化,實際上子類的靜態變量和靜態初始化塊的初始化是在父類的變量、初始化塊和構造器初始化之前就完成了。

 

*******************************************************

*******************************************************

    那麼對於靜態變量和靜態初始化塊之間、變量和初始化塊之間的先後順序又是怎樣呢?是否靜態變量總是先於靜態初始化塊,變量總是先於初始化塊就被初始化了呢?實際上這取決於它們在類中出現的先後順序。我們以靜態變量和靜態初始化塊爲例來進行說明。

    同樣,我們還是寫一個類來進行測試:

  1. public class TestOrder {   
  2.     // 靜態變量   
  3.     public static TestA new TestA();   
  4.        
  5.     // 靜態初始化塊   
  6.     static {   
  7.         System.out.println("靜態初始化塊");   
  8.     }   
  9.        
  10.     // 靜態變量   
  11.     public static TestB new TestB();   
  12.   
  13.     public static void main(String[] args) {   
  14.         new TestOrder();   
  15.     }   
  16. }   
  17.   
  18. class TestA {   
  19.     public TestA() {   
  20.         System.out.println("Test--A");   
  21.     }   
  22. }   
  23.   
  24. class TestB {   
  25.     public TestB() {   
  26.         System.out.println("Test--B");   
  27.     }   
  28.  

運行上面的代碼,會得到如下的結果: 

  1. Test--A
  2. 靜態初始化塊
  3. Test--B

 

*******************************************************

*******************************************************

參考:JAVA 初始化順序

//JAVA初始化分兩大步
//A、類的加載
//
//        先加載父類,在加載子類
//
//        加載父類後,完成靜態動作【靜態變量、靜態代碼塊(主動執行僅一次)】(按代碼順序)、【靜態方法(被動執行)】
//
//        加載子類後,完成靜態動作【靜態變量、靜態代碼塊(主動執行僅一次)】(按代碼順序)、【靜態方法(被動執行)】
//
//B、類的實例化
//
//        先實例化父類,在實例化子類
//       
//        實例化父類,完成實例化【成員變量、初始化塊】(按代碼順序)、【父類構造方法】、【成員方法(被動執行)】
//   
//        實例化子類,完成實例化【成員變量、初始化塊】(按代碼順序)、【子類構造方法】、【成員方法(被動執行)】


//注:類裝載步驟(詳解A步驟)
//     在Java中,類裝載器把一個類裝入Java虛擬機中,要經過三個步驟來完成:裝載、鏈接和初始化,其中鏈接又可以分成校驗、準備和解析三步,除了解析外,其它步驟是嚴格按照順序完成的,各個步驟的主要工作如下:
//裝載:查找和導入類或接口的二進制數據;
//鏈接:執行下面的校驗、準備和解析步驟,其中解析步驟是可以選擇的;
//校驗:檢查導入類或接口的二進制數據的正確性;
//準備:給類的靜態變量分配並初始化存儲空間;
//解析:將符號引用轉成直接引用;
//初始化:激活類的靜態變量的初始化Java代碼和靜態Java代碼塊。
//初始化類中屬性是靜態代碼塊的常用用途,但只能使用一次。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章