類載入運行的全過程 當用java命令運行某個main函數時,首先需要類載入器把主類載入到JVM記憶體中。 通過Java命令執行代碼的大致流程為 將編譯好的位元組碼class文件通過java命令,在win操作系統就是一個java.exe文件,這個文件底層是c++語言實現的,通過這個文件調用底層jvm.dl ...
類載入運行的全過程
當用java命令運行某個main函數時,首先需要類載入器把主類載入到JVM記憶體中。
通過Java命令執行代碼的大致流程為
將編譯好的位元組碼class文件通過java命令,在win操作系統就是一個java.exe文件,這個文件底層是c++語言實現的,通過這個文件調用底層jvm.dll文件創建Java虛擬機,這個jvm.dll文件也是c++語言實現的就是一些類庫。在創建JVM虛擬機的過程中會通過c++語言創建一個引導類載入器。最終由C++語言調用java代碼創建JVM啟動器Launcher,該類由引導類載入器創建其他類載入器,最終調用的Launcher類的getLauncher()方法,這個方法創建載入了擴展類載入器,應用程式類載入器。最終調用loadClass()方法實現類的載入,這個方法體現了雙親委派機制。
java裡面有一下幾種類載入器:
引導類載入器:載入jre/lib下核心jar包 如rt.jar charset.jar
擴展類載入器:載入jre/lib/ext下麵的jar包
應用程式類載入器:載入自己寫的java類
自定義類載入器:負責載入用戶自定義路徑下的類包
如果想要擺脫雙親委派機制可以重寫loadclass方法
//ClassLoader的loadClass方法,裡面實現了雙親委派機制 2 protected Class<?> loadClass(String name, boolean resolve) 3 throws ClassNotFoundException 4 { 5 synchronized (getClassLoadingLock(name)) { 6 // 檢查當前類載入器是否已經載入了該類 7 Class<?> c = findLoadedClass(name); 8 if (c == null) { 9 long t0 = System.nanoTime(); 10 try { 11 if (parent != null) { //如果當前載入器父載入器不為空則委托父載入器載入該類 12 c = parent.loadClass(name, false); 13 } else { //如果當前載入器父載入器為空則委托引導類載入器載入該類 14 c = findBootstrapClassOrNull(name); 15 } 16 } catch (ClassNotFoundException e) { 17 // ClassNotFoundException thrown if class not found 18 // from the non‐null parent class loader 19 } 2021 if (c == null) { 22 // If still not found, then invoke findClass in order 23 // to find the class. 24 long t1 = System.nanoTime(); 25 //都會調用URLClassLoader的findClass方法在載入器的類路徑里查找並載入該類 26 c = findClass(name); 27 28 // this is the defining class loader; record the stats 29 sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 ‐ t0); 30 sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); 31 sun.misc.PerfCounter.getFindClasses().increment(); 32 } 33 } 34 if (resolve) { //不會執行 35 resolveClass(c); 36 } 37 return c; 38 } 39 }
如果想自己定義類載入器,定義要載入自己的類路徑則重新編寫findClass()方法;
為什麼jdk設計者要對類載入實現雙親委派機制?
1.沙箱安全機制 自己寫的java.lang.String.class類不會被載入,這樣便可以防止核心API庫被隨意篡改
2.避免類的重覆載入 父類載入過得類,子類沒必要重覆載入