百度一下java的static塊執行時機,搜出來的文章有兩種說法,第一種說static塊是在類的加載時執行(包括我看過的Java視頻都是這么說的),另一種則是反對第一種說法,即static塊並不是在類的加載時執行的,而是在類的初始化時執行的;誰對誰錯,事實用代碼證明。
類的運行步驟
類的運行可分為三個步驟:裝載、連接、初始化
- 裝載:查找和導入Class文件
- 連接:把類的二進制數據合並到JRE中,又分為三個步驟
- 校驗:檢查載入Class文件數據的正確性
- 准備:給類的靜態變量分配存儲空間
- 解析:將符號引用轉成直接引用
- 初始化:對類的靜態變量,靜態代碼塊執行初始化操作(看到這里,結論就已經出來了,但我們還是要用代碼來說話)
用反射機制來證明static塊的執行時機
- 有一個含static塊的類:
class MyStatic {
static {
System.out.println("靜態代碼塊執行了");
}
MyStatic() {}
}
- 先來看一個錯誤的例子(我看的視頻里就是用這個例子來證明static塊是在類的加載時執行的)
public class Test {
public static void main(String[] args) {
Test test = new Test();
try{
Class.forName("MyStatic"); //誤認為forName方法運行類只完成加載,實際上forName方法運行時已執行了類的初始化
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
運行結果
靜態代碼塊執行了
靜態代碼塊執行了,然而這並不能代表什么,因為
Class.forName("MyStatic");
等同於
Class.forName("MyStatic", true, test.getClass().getClassLoader());
其中第二個參數指明了是否進行類初始化,將其改成false再試一次
public class Test {
Test() {}
public static void main(String[] args) {
Test test = new Test();
try{
Class.forName("MyStatic", false, test.getClass().getClassLoader());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
這時MyStatic類並沒有進行初始化過程,而程序運行沒有任何輸出,得出結論:
Java中靜態代碼塊是在類的初始化過程中執行的,並不是在類的裝載時執行的