1)類載入的過程是怎麼樣的?①載入:根據具體需求,選擇合適的載入器(Bootstrap ClassLoader不可直接獲取、Extension ClassLoader、系統、自定義)來控制位元組流的獲取,實例化一個Class對象作為數據訪問入口。②連接(驗證,準備,解析):(JVM)a.驗證,在載入階 ...
1)類載入的過程是怎麼樣的?
①載入:根據具體需求,選擇合適的載入器(Bootstrap ClassLoader不可直接獲取、Extension ClassLoader、系統、自定義)來控制位元組流的獲取,實例化一個Class對象作為數據訪問入口。
②連接(驗證,準備,解析):(JVM)
a.驗證,在載入階段不能保證位元組流的來源就是由純粹的java代碼編譯過來的,也有可能是在網路中下載的、別人給的文件、zip包等,所以要進行驗證(文件格式驗證、元數據驗證、位元組碼驗證、符號引用驗證);
b.準備,給類變數(靜態變數)分配記憶體並設置初始值的階段;(註意:類變數有無final修飾)
c.解析,將常量池內的符號引用替換為直接引用;
③初始化:真正執行Java代碼,只會被執行一次。這裡還要通過類構造器,將指定的初始值賦予給靜態變數。(註意:此時與上面在準備階段為類變數設置初始值 不同);
2)兩個不同的類載入器載入同一個類,如何進行區分和隔離?
雙親委派機制
觀察ClassLoader的loadClass()方法:
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
protected synchronized Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
Class c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
}
if (c == null) {
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
得出:當接到載入類的請求時,先檢查是否已經被載入過,判斷沒有被載入過後,先將載入任務委托給父載入完成類載入任務,因此所有載入請求都應該傳送到啟動類載入其中,只有父載入器無法完成此載入任務時拋出異常,同時自己才去載入。
又因為各個載入器之間是一種組合的關係,都有各自的分工,不同的類載入器實例載入的話,會在方法區產生兩個不同的類,彼此不可見,並且在堆中生成不同Class實例。在請求委派的過程中,每一個層次類載入器都要如上操作,實現層級委任。
從此保證了,不同ClassLoader對象載入的同名類屬於不同的類型,它們之間不能相互轉化和相容。同一類的類載入器,不同的對象載入出來的類也不是同一個類。從而達到區分和隔離的效果。