【轉】java static代碼塊執行時機

之前一直認爲static塊是在class load的時候執行,今天在驗證Spring初始化Context loader的時候,發現bean的static塊並沒有執行。

Java代碼:

 Class A{   
    static{
       System.out.println("static block invoked!")
    }
 }

那麼static塊到底在什麼時候運行的呢?如果瞭解JVM原理,我們知道,一個類的運行分爲以下步驟:

  1. 裝載
  2. 連接
  3. 初始化

其中裝載階段又三個基本動作組成:

  1. 通過類型的完全限定名,產生一個代表該類型的二進制數據流
  2. 解析這個二進制數據流爲方法區內的內部數據結
  3. 構創建一個表示該類型的java.lang.Class類的實例

另外如果一個類裝載器在預先裝載的時遇到缺失或錯誤的class文件,它需要等到程序首次主動使用該類時才報告錯誤。

連接階段又分爲三部分:

  1. 驗證,確認類型符合Java語言的語義,檢查各個類之間的二進制兼容性(比如final的類不用擁有子類等),另外還需要進行符號引用的驗證。
  2. 準備,Java虛擬機爲類變量分配內存,設置默認初始值。
  3. 解析(可選的) ,在類型的常量池中尋找類,接口,字段和方法的符號引用,把這些符號引用替換成直接引用的過程。

當一個類被主動使用時,Java虛擬就會對其初始化,如下六種情況爲主動使用:

  1. 當創建某個類的新實例時(如通過new或者反射,克隆,反序列化等)
  2. 當調用某個類的靜態方法時
  3. 當使用某個類或接口的靜態字段時
  4. 當調用Java API中的某些反射方法時,比如類Class中的方法,或者java.lang.reflect中的類的方法時
  5. 當初始化某個子類時
  6. 當虛擬機啓動某個被標明爲啓動類的類(即包含main方法的那個類)

Java編譯器會收集所有的類變量初始化語句和類型的靜態初始化器,將這些放到一個特殊的方法中:clinit。

實際上,static塊的執行發生在“初始化”的階段。初始化階段,jvm主要完成對靜態變量的初始化,靜態塊執行等工作。

下面我們看看執行static塊的幾種情況:

  1. 第一次new A()的過程會打印"";因爲這個過程包括了初始化
  2. 第一次Class.forName("A")的過程會打印"";因爲這個過程相當於Class.forName("A",true,this.getClass().getClassLoader());
  3. 第一次Class.forName("A",false,this.getClass().getClassLoader())的過程則不會打印""。因爲false指明瞭裝載類的過程中,不進行初始化。不初始化則不會執行static塊。
發佈了80 篇原創文章 · 獲贊 143 · 訪問量 35萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章