JVM類加載機制詳解。本站提示廣大學習愛好者:(JVM類加載機制詳解)文章只能為提供參考,不一定能成為您想要的結果。以下是JVM類加載機制詳解正文
一、先看看編寫出的代碼的執行過程:
二、研究類加載機制的意義
從上圖可以看出,類加載是Java程序運行的第一步,研究類的加載有助於了解JVM執行過程,並指導開發者采取更有效的措施配合程序執行。
研究類加載機制的第二個目的是讓程序能動態的控制類加載,比如熱部署等,提高程序的靈活性和適應性。
三、類加載的一般過程
原理:雙親委托模式
1、尋找jre目錄,尋找jvm.dll,並初始化JVM;
2、產生一個Bootstrap Loader(啟動類加載器);
3、Bootstrap Loader自動加載Extended Loader(標准擴展類加載器),並將其父Loader設為Bootstrap Loader。
4、Bootstrap Loader自動加載AppClass Loader(系統類加載器),並將其父Loader設為Extended Loader。
5、最後由AppClass Loader加載HelloWorld類。
四、類加載器的特點
1、運行一個程序時,總是由AppClass Loader(系統類加載器)開始加載指定的類。
2、在加載類時,每個類加載器會將加載任務上交給其父,如果其父找不到,再由自己去加載。
3、Bootstrap Loader(啟動類加載器)是最頂級的類加載器了,其父加載器為null.
五、類加載器的獲取
很容易,看下面例子
public class HelloWorld { public static void main(String[] args) { HelloWorld hello = new HelloWorld(); Class c = hello.getClass(); ClassLoader loader = c.getClassLoader(); System.out.println(loader); System.out.println(loader.getParent()); System.out.println(loader.getParent().getParent()); } }
打印結果:
sun.misc.Launcher$AppClassLoader@19821f
sun.misc.Launcher$ExtClassLoader@addbf1
null
從上面的結果可以看出,並沒有獲取到ExtClassLoader的父Loader,原因是Bootstrap Loader(啟動類加載器)是用C語言實現的,找不到一個確定的返回父Loader的方式,於是就返回null。
六、類的加載
類加載有三種方式:
1、命令行啟動應用時候由JVM初始化加載
2、通過Class.forName()方法動態加載
3、通過ClassLoader.loadClass()方法動態加載
三種方式區別比較大,看個例子就明白了:
package zhongqiu.common.base; public class ClassLoadDemo { static { System.out.println("ClassLoadDemo靜態初始化塊執行了!"); } public static void main(String[] args) throws ClassNotFoundException { ClassLoader loader2 = ClassLoadDemo.class.getClassLoader(); System.out.println(loader2); // 使用ClassLoader.loadClass()來加載類,不會執行初始化塊 // loader2.loadClass("zhongqiu.test.Test"); // 使用Class.forName()來加載類,默認會執行初始化塊 // Class.forName("zhongqiu.test.Test"); // 使用Class.forName()來加載類,並指定ClassLoader,初始化時不執行靜態塊 Class.forName("zhongqiu.test.Test", false, loader2); } }
七、自定義ClassLoader
package zhongqiu.common.base.classload; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; public class MyClassLoader { @SuppressWarnings("resource") public static void main(String[] args) throws MalformedURLException, ClassNotFoundException, IllegalAccessException, InstantiationException { URL url = new URL("file:/D:/javaworkspace/JavaCommon/src/"); ClassLoader myloader = new URLClassLoader(new URL[] { url }); Class c = myloader.loadClass("zhongqiu.common.base.classload.Test"); Test t3 = (Test) c.newInstance(); } }
在Java.lang包裡有個ClassLoader類,ClassLoader 的基本目標是對類的請求提供服務,按需動態裝載類和資源,只有當一個類要使用(使用new 關鍵字來實例化一個類)的時候,類加載器才會加載這個類並初始化。一個Java應用程序可以使用不同類型的類加載器。例如Web Application Server中,Servlet的加載使用開發商自定義的類加載器, java.lang.String在使用JVM系統加載器,Bootstrap Class Loader,開發商定義的其他類則由AppClassLoader加載。在JVM裡由類名和類加載器區別不同的Java類型。因此,JVM允許我們使用不同的加載器加載相同namespace的java類,而實際上這些相同namespace的java類可以是完全不同的類。這種機制可以保證JDK自帶的java.lang.String是唯一的。
八、為什麼要使用這種雙親委托模式呢?
因為這樣可以避免重復加載,當父親已經加載了該類的時候,就沒有必要子ClassLoader再加載一次。
考慮到安全因素,我們試想一下,如果不使用這種委托模式,那我們就可以隨時使用自定義的String來動態替代java核心api中定義類型,這樣會存在非常大的安全隱患,而雙親委托的方式,就可以避免這種情況,因為String已經在啟動時被加載,所以用戶自定義類是無法加載一個自定義的ClassLoader。
以上就是本文的全部內容,希望本文的內容對大家的學習或者工作能帶來一定的幫助,同時也希望多多支持!