參考鏈接: Java中的初始化程序塊Initializer Block
關于這個問題,本文不扯理論,直接上代碼,通過結果來驗證結論,廢話少說,測試代碼如下:?
public class StaticTest {
?
? ? public static StaticMember staticMember = new StaticMember();
?
? ? static {
? ? ? ? System.out.println("static code initializer ");
? ? }
?
? ? private static class InnerClass {
? ? ? ? private static StaticTest staticTest = new StaticTest("load from InnerClass");
? ? }
?
? ? public StaticTest() {
? ? }
?
? ? public StaticTest(String a) {
? ? ? ? System.out.println(a);
? ? }
?
? ? public static void f(){
?
? ? }
?
? ? public void d(){
?
? ? }
?
? ? public static void e(){
? ? ? ? InnerClass.staticTest.d();
? ? }
}?
public class StaticMember {
? ? public StaticMember(){
? ? ? ? System.out.println("StaticMember");
? ? }
}?
在StaticTest 測試類中我寫了三種靜態域分別是靜態成員變量,靜態代碼塊以及靜態內部類,下面通過不同的case測試上面三種靜態域何時被初始化。? 測試case代碼:?
public class Main {
? ? static boolean flg;
?
? ? public static void main(String[] args) {
?
? ? ? ? /**case1**/
? ? ? ? //不會執行靜態代碼塊, 靜態成員變量不會初始化, 也不會加載靜態內部類
? ? ? ? String simpleName = StaticTest.class.getSimpleName();
?
? ? ? ? /**case2**/
? ? ? ? //會執行靜態代碼塊, 靜態成員變量會初始化, 不會加載靜態內部類
? ? ? ? //輸出 StaticMember
? ? ? ? //? ? static code initializer
? ? ? ? StaticMember staticMember = StaticTest.staticMember;
?
? ? ? ? /**case3**/
? ? ? ? //會執行靜態代碼塊, 靜態成員變量會初始化, 不會加載靜態內部類
? ? ? ? //輸出 StaticMember
? ? ? ? //? ? static code initializer
? ? ? ? new StaticTest();
?
? ? ? ? /**case4**/
? ? ? ? //會執行靜態代碼塊, 靜態成員變量會初始化, 不會加載靜態內部類
? ? ? ? //輸出 StaticMember
? ? ? ? //? ? static code initializer
? ? ? ? StaticTest.f();
?
? ? ? ? /**case5**/
? ? ? ? //不會執行靜態代碼塊, 靜態成員變量不會初始化, 也不會加載靜態內部類
? ? ? ? if (flg) {
? ? ? ? ? ? test();
? ? ? ? }
?
? ? ? ? /**case6**/
? ? ? ? //會執行靜態代碼塊, 靜態成員變量會初始化, 同時加載靜態內部類
? ? ? ? // 輸出:StaticMember
? ? ? ? //? ? ? static code initializer
? ? ? ? //? ? ? load from InnerClass
? ? ? ? StaticTest.e();
? ? }
?
? ? private static void test(){
? ? ? ? StaticTest.f();
? ? ? ? StaticTest.e();
? ? }
?
}?
通過上面每一種代碼測試case的輸出結果,可以得出如下結論:?
靜態成員變量和靜態代碼塊(static{})只有在類被調用的時候才會初始化。? 這里是指在運行時真正被使用到才會被初始化,如果是在編譯時被使用到,但在運行時沒有使用到也不會被初始化,比如上面的case5。靜態內部類只有當被外部類調用到的時候才會初始化。? 這里也是指在運行時,也就是說不在于你在編輯器中有沒有寫調用的代碼,而是你寫的這段調用代碼運行時是否會被真正執行到。在只使用了外部類,但是沒有使用內部類的情況下,內部類里面的東西不會被初始化。?
關于case1的情況,直接引用StaticTest.class不會初始化靜態變量和靜態代碼塊,而直接new StaticTest()就會,為什么呢?因為JVM在加載類的過程中分為五個階段:加載、驗證、準備、解析、初始化,StaticTest.class的方式發生在第一個階段,這個階段會在Java堆中創建java.lang.Class的實例,而變量和靜態塊是發生在最后一個初始化的階段,具體參考:Java虛擬機 類加載的過程, Chapter 5. Loading, Linking, and Initializing