一、類的加載過程
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-hk/n/368935.html