首先要明白的是,在Java代碼中,類型(class、interface、枚舉等,不是對象)的加載、連接與初始化過程都是在程序運行期間完成的。
Java虛擬機與程序的生命週期
在如下的幾種情況下,Java虛擬機將會結束生命週期
- 執行了System.exit()方法
- 程序執行結束
- 程序在執行過程中遇到了異常或錯誤而異常終止
- 由於操作系統出現錯誤而導致Java虛擬機進程終止
類的加載連接與初始化過程詳解
如上圖所示,類的加載主要分爲三個階段,分別是:
- 加載:指的是將類的.class文件中的二進制數據讀入到內存中,將其放在運行時數據區的方法區中,然後在內存中創建一個java.lang.Class對象(JVM規範並未說明Class對象位於哪裏,HotSpot虛擬機將其放在了方法區中)用來封裝類在方法區內的數據結構
- 連接:連接簡要來說就是將類與類之間的關係確定好,它又被分爲三個過程,依次是:
- 驗證:確保被加載類的正確性
- 準備:爲類的靜態變量分配內存,並將其初始化爲默認值(並不用定義時賦的初值)eg:int類型變量默認值爲0;
- 把類的符號引用轉換爲直接引用
- 初始化:爲類的靜態變量賦予正確的初始值。例如:public static int a=1; 那麼初始化類時會將1賦給變量a,1就是a的初始值
除了以上三個階段,類的加載其實還有使用和卸載兩個階段,這兩個階段在實際開發中接觸不多,這裏不再介紹。
Java程序對類的使用方式
Java程序對類的使用方式分爲兩種,一種是主動使用,一種是被動使用。而主動使用的方式又分爲以下七種:
- 創建類的實例(即通過new關鍵字創建的實例)
- 訪問某個類或接口的靜態變量或者對該靜態變量賦值
- 調用類的靜態方法
- 反射(如Class.forName(“com.test.Test”))
- 初始化一個類的子類
- Java虛擬機啓動時被標明爲啓動類的類(即擁有main方法)
- JDK 1.7開始提供的靜態語言支持:java.lang.invoke.MethodHandle實例的解析結果REF_getStatic,REF_putStatic,REF_invokeStatic句柄對應的類沒有初始化,則進行初始化
那麼被動使用就是除以上七種使用方式以外的其他方式都是屬於被動使用,並且被動使用是不會導致類的初始化的。所有的Java虛擬機實現都是在每個類或接口被Java程序“首次主動使用”時才初始化他們,並且只會被初始化一次。