類加載
- 在Java代碼中,類型(class 、interface、 enum etc)的加載(將字節碼從磁盤加載到內存),連接(類與類之間的關係的連接)與初始化過程都是在程序運行期間完成的,加載,連接,初始化順序不是固定的,不同的虛擬機實現不一樣。
- 提供了更大的靈活性,增加了更多的可能性。
類加載器深入剖析
- Java虛擬機與程序的週期
- 在如下幾種情況下,Java虛擬機將結束生命週期。
- 執行了System.ext()方法。
- 程序正常執行結束
- 程序在執行過程中遇到了異常或錯誤而異常終止。
- 由於操作系統錯誤而導致Java虛擬機進程終止。 -
類的加載、連接與初始化
- 加載:查找並加載類的二進制數據
- 連接:
- 驗證:確保被加載類的正確性。
- 準備:爲類的靜態變量分配內存,並將其初始化爲默認值。
- 解析:把類中的符號引用裝換爲直接引用。
初始化:爲類的靜態變量賦予正確的初始值。
Java程序對類的使用方式可分爲2種:
- 主動使用
- 被動使用所有的Java虛擬機實現必須在每個類或者接口被Java程序“首次主動使用”時才初始化他們。
主動使用(七種)
- 創建類的實例。
- 訪問某個類或者接口的靜態變量,或者對該靜態變量賦值。
- 調用類的靜態方法。
- 反射 (如Class.forName(“com.test.Test”))
- 初始化一個類的子類
- Jav啊虛擬機啓動時被標明爲啓動類的類(Java Test)
- JDK1.7開始提供的動態 語言支持:
Java.lang.invoke.MethodHandle實例的解析結果REF_getStattic REF_putStatic REF_invokeStatic句柄對應的類如果沒有初始化,則初始化(瞭解)
除了以上七中情況,其他使用Java類的方式都被看做是對類的被動使用,都不會導致類的初始化(指的是加載,連接,初始化這個步驟的初始化)
實例介紹:
public class MyTest {
/*
對於靜態字段來說,只有直接定義該字段的類纔會被初始化
當一個類初始化時,要求其父類全部都已經初始化完畢了
-XX:+TraceClassLoading 用於追蹤類的加載信息並打印出來
-XX:+<option> 表示開啓option選項
-XX:-<option> 表示關閉option選項
-XX:<option>=<value>,表示將option的選項的值設置爲value
*/
public static void main(String[] args) {
//直接使用父類的變量 ,子類不會初始化,雖有用了子類的標識符
System.out.println(MyChild.str);
/*
MyParent1 static block
hello world
*/
//直接調用子類的變量 會首先初始化父類,然後再初始化子類
// System.out.println(MyChild.str2);
/*
MyParent1 static block
MyChild static bloack
welcome
*/
}
}
class MyParent1{
public static String str = "hello world";
static{
System.out.println("MyParent1 static block");
}
}
class MyChild extends MyParent1{
public static String str2 = "welcome";
static{
System.out.println("MyChild static bloack");
}
}
類的加載:
- 類的加載指的是將類的.class文件中的二進制數據讀入到內存中,將其放在運行時數據區的方法區,然後在內存中創建一個Java.lang.Class對象(規範並未說明Class對象位於哪裏,HotPot虛擬機將其放在了方法區中)用來封裝類在方法區內的數據結構。
- 加載.class文件的方式
- 從本地系統中直接加載
- 通過網絡下載.class文件
- 從zip,jar等歸檔文件中加載.class文件
- 從專有數據庫中提取 .class文件
- 將Java源文件動態編譯爲.class文件
類的使用與卸載
- 使用 :正常的使用,調用類的方法等
- 卸載 :從內存中卸載。