一、類的載入過程
Java虛擬機在運行時會動態載入需要用到的類,稱為「類的載入」。類的載入可以分三個步驟:載入、連接和初始化。
1、載入:在載入階段,類載入器首先通過類的全限定名來讀取類的二進位數據,並將其存放在JVM的方法區中。類的全限定名是包含了包名的全稱,如”java.lang.Object”。
2、連接:在連接階段,類的驗證、準備和解析都會在此階段進行。
(1)驗證:驗證是確保被載入的類符合JVM規範的一個重要步驟。如果類的驗證不通過,則會拋出異常並終止程序運行。
public class VerifyTest { public static void main(String[] args) { System.out.println("hello"); } }
(2)準備:準備是為靜態變數分配內存空間並設置默認值的過程。在此階段,類中聲明的所有static變數都會賦值為默認值。
public class PrepareTest { private static int num; private static String str; public static void main(String[] args) { System.out.println(num); // 輸出 0 System.out.println(str); // 輸出 null } }
(3)解析:解析是將符號引用轉換為直接引用的過程。在解析階段,會將類、介面、欄位和方法的符號引用轉換為直接引用。
public class ResolveTest { public static void main(String[] args) { System.out.println("hello world"); } }
3、初始化:在初始化階段,類的靜態變數和靜態塊會按照程序中的順序依次執行。
public class StaticBlockTest { private static String str = "hello world"; static { System.out.println(str); } public static void main(String[] args) { System.out.println("main method"); } }
二、類的載入器
Java虛擬機中有三類類載入器:
1、啟動類載入器:負責載入JRE/lib目錄下的核心類庫,如rt.jar等。
2、擴展類載入器:負責載入JRE/lib/ext目錄下的擴展類庫。
3、應用程序類載入器:負責載入用戶類路徑上所指定的類庫,一般是項目中的class文件和jar包。
除了這三個類載入器之外,還可以通過編寫自定義類載入器來實現特定的載入需求。
三、類的載入機制
類的載入機制是指類的載入器在載入類時的一系列策略和規則。主要有以下幾種:
1、雙親委派模型:Java虛擬機中的類載入器採用了雙親委派模型。即在類載入器載入某個類時,先將這個任務委託給父類載入器完成,如果父類載入器無法完成,則由子類載入器嘗試去載入。
public class ClassLoaderTest { public static void main(String[] args) { ClassLoader loader = ClassLoaderTest.class.getClassLoader(); while (loader != null) { System.out.println(loader.getClass().getName()); loader = loader.getParent(); } } }
2、負責命名空間:每個類載入器都擁有自己的命名空間。命名空間是由該載入器及其所有父類載入器所載入的類所組成的集合。同一個命名空間內的類是有相同的類全稱的,不同命名空間內的類是由不同的類全稱的,即使class文件的位元組碼相同。
public class NameSpaceTest { public static void main(String[] args) throws Exception { MyClassLoader loader1 = new MyClassLoader("loader1"); loader1.setPath("C:\\myapp\\loader1\\"); MyClassLoader loader2 = new MyClassLoader(loader1, "loader2"); loader2.setPath("C:\\myapp\\loader2\\"); Class clazz1 = loader1.loadClass("com.myapp.Test"); Class clazz2 = loader2.loadClass("com.myapp.Test"); System.out.println("clazz1的類載入器為:" + clazz1.getClassLoader().getClass().getName()); System.out.println("clazz2的類載入器為:" + clazz2.getClassLoader().getClass().getName()); System.out.println("clazz1和clazz2是否相等:" + (clazz1 == clazz2)); } }
3、父類載入器對子類載入器不可見:子類載入器可以訪問父類載入器所載入的類,而父類載入器無法訪問子類載入器所載入的類。
4、系統類載入器和應用程序類載入器都是有啟動類載入器所載入的。
原創文章,作者:IPQWS,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/368935.html