引發問題的來源:最近在看比較深入的JVM相關的書,不得不感慨,JVM确實是比較深奧,很多地方難以了解不說,在網上還找不到什麼資料,發現一個左思右想都想不明白的問題上網來搜尋,結果基本上都是從書上copy下來的東西,還是不能了解。
問題的出現:今天突然想到一個這樣的問題,就是類變量也就是靜态變量的初始化問題。以前的範範了解是靜态變量在類加載的時候就會初始化,反正是在初始化堆記憶體的之前會初始化靜态變量,知道是這麼一回事,但是不知其是以然。因為類加載其實也是有很多個步驟的,比如加載-連接配接-初始化。以前了解的類加載的意思就有點歧義,究竟是加載-連接配接叫做類加載還是僅僅是加載-連接配接這其中的加載呢?我們知道Class.forName("ClassName")與ClassName.class都會傳回一個類的Class對象(這個東西不好了解,但是一旦了解了這玩意,對Java的反射機制的了解就又會上升一個高度),但是這兩個有什麼差別呢?
帶着這兩個問題,上網查了一下,然後自己寫了測試代碼來測試。
1.定義一個類MyClass:裡面有一個内部内,還有一個靜态變量和一個靜态代碼塊。
public class MyClass {
static InnerClass in = new InnerClass();
static {
System.out.println("static block");
}
static class InnerClass {
static {
System.out.println("inner");
}
}
}
2.測試代碼:
@SuppressWarnings("all")
public class MyClassTest {
@Test
public void testMyClass() {
try {
Class c1 = MyClass.class;
// 沒有任何輸出
Class c2 = Class.forName("chain.MyClass");
// 輸出:
// inner
// static block
} catch (Exception e) {
e.printStackTrace();
}
}
}
根據輸出結果可以發現:.class僅僅是把類加載進JVM而沒有做類的初始化,而forName的形式是初始化了類的(包括初始化靜态變量和靜态代碼快),他們都進行類加載,唯一差別就是初始化類變量與否,這是第二個問題的答案,第一個問題的答案顯而易見,我以前了解的靜态變量的加載其實是進行的是forName的結果。