java 中靜態代碼塊執行的時機

一、簡單認爲JAVA靜態代碼塊在類被加載時就會自動執行  是錯誤的java

class MyClass1 {
    static {//靜態塊
        System.out.println("static block ");
    }
}
public class Main {
 
    Class[] classArray = {
            MyClass1.class//這樣引用該類,必然須要將該類加載到虛擬機中
    };
    public static void main(String[] args){
        System.out.println("hello word");//執行結果:並無輸出" static bolck" 
    }
 
}

二、正解:static塊真正的執行時機數據結構

一個類的運行分爲如下步驟:jvm

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

裝載階段this

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

補充:若是一個類裝載器在預先裝載的時遇到缺失或錯誤的class文件,它須要等到程序首次主動使用該類時才報告錯誤code

 鏈接階段接口

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

當一個類被主動使用時,Java虛擬就會對其初始化內存

以下六種狀況爲主動使用:get

  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塊
相關文章
相關標籤/搜索