依上圖中當class字節碼文件被jvm虛擬機加載到內存中依次經過
- 連接
- 驗證:對字節碼進行驗證
- 準備:給靜態變量分配內存并賦予變量類型各自的默認值(注:基本類型為0或false,對象為null,static final修飾的常量直接賦予相應的值)
- 解析:類中符號引用轉換成直接引用
- 初始化:為類的靜態變量/靜態語句塊初始化相應的值
而類的初始化契機是:類在被第一次主動使用的情況下,主動使用包括以下6中情況:- 使用new關鍵字實例化對象時。
- 調用某個類的靜態方法時。
- 讀取或設置類的靜態字段時(被final修飾、已在編譯期把結果放入常量池的除外)。
- 使用java.lang.reflect包的方法對類進行反射調用。
- 初始化某個類的子類時。
- 虛擬機啟動時被標明為啟動類(包含main方法的類)。
從上面我們知道了靜態成員變量的初始化發生在類的 初始化階段,而要實例化一個對象就必須先去加載、連接、以及初始化該類,才能去使用該類去實例化對象,而非
靜態成員變量的初始化發生在對象的實例化過程中。如下例子可以看出當一個類被第一次主動使用靜態塊或靜態成員變量會被初始化。
1 package com.space.equalstest; 2 3 public class Dog { 4 public static String name = "tom"; 5 6 static { 7 System.out.println("Dog init"); 8 } 9 10 public static void info() { 11 System.out.println("a dog"); 12 } 13 }
1 package com.space.equalstest; 2 3 public class Test { 4 public static void main(String[] args) { 5 Dog.info();//首次主動使用進行初始化 6 Dog.info();//不會再去初始化 7 } 8 }
輸出結果:
1 Dog init
2 a dog
3 a dog