JVM類(lèi)加載機(jī)制詳解
一、先看看編寫(xiě)出的代碼的執(zhí)行過(guò)程:
二、研究類(lèi)加載機(jī)制的意義
從上圖可以看出,類(lèi)加載是Java程序運(yùn)行的第一步,研究類(lèi)的加載有助于了解JVM執(zhí)行過(guò)程,并指導(dǎo)開(kāi)發(fā)者采取更有效的措施配合程序執(zhí)行。
研究類(lèi)加載機(jī)制的第二個(gè)目的是讓程序能動(dòng)態(tài)的控制類(lèi)加載,比如熱部署等,提高程序的靈活性和適應(yīng)性。
三、類(lèi)加載的一般過(guò)程
原理:雙親委托模式
1、尋找jre目錄,尋找jvm.dll,并初始化JVM;
2、產(chǎn)生一個(gè)Bootstrap Loader(啟動(dòng)類(lèi)加載器);
3、Bootstrap Loader自動(dòng)加載Extended Loader(標(biāo)準(zhǔn)擴(kuò)展類(lèi)加載器),并將其父Loader設(shè)為Bootstrap Loader。
4、Bootstrap Loader自動(dòng)加載AppClass Loader(系統(tǒng)類(lèi)加載器),并將其父Loader設(shè)為Extended Loader。
5、最后由AppClass Loader加載HelloWorld類(lèi)。
四、類(lèi)加載器的特點(diǎn)
1、運(yùn)行一個(gè)程序時(shí),總是由AppClass Loader(系統(tǒng)類(lèi)加載器)開(kāi)始加載指定的類(lèi)。
2、在加載類(lèi)時(shí),每個(gè)類(lèi)加載器會(huì)將加載任務(wù)上交給其父,如果其父找不到,再由自己去加載。
3、Bootstrap Loader(啟動(dòng)類(lèi)加載器)是最頂級(jí)的類(lèi)加載器了,其父加載器為null.
五、類(lèi)加載器的獲取
很容易,看下面例子
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()); } }
打印結(jié)果:
sun.misc.Launcher$AppClassLoader@19821f
sun.misc.Launcher$ExtClassLoader@addbf1
null
從上面的結(jié)果可以看出,并沒(méi)有獲取到ExtClassLoader的父Loader,原因是Bootstrap Loader(啟動(dòng)類(lèi)加載器)是用C語(yǔ)言實(shí)現(xiàn)的,找不到一個(gè)確定的返回父Loader的方式,于是就返回null。
六、類(lèi)的加載
類(lèi)加載有三種方式:
1、命令行啟動(dòng)應(yīng)用時(shí)候由JVM初始化加載
2、通過(guò)Class.forName()方法動(dòng)態(tài)加載
3、通過(guò)ClassLoader.loadClass()方法動(dòng)態(tài)加載
三種方式區(qū)別比較大,看個(gè)例子就明白了:
package zhongqiu.common.base; public class ClassLoadDemo { static { System.out.println("ClassLoadDemo靜態(tài)初始化塊執(zhí)行了!"); } public static void main(String[] args) throws ClassNotFoundException { ClassLoader loader2 = ClassLoadDemo.class.getClassLoader(); System.out.println(loader2); // 使用ClassLoader.loadClass()來(lái)加載類(lèi),不會(huì)執(zhí)行初始化塊 // loader2.loadClass("zhongqiu.test.Test"); // 使用Class.forName()來(lái)加載類(lèi),默認(rèn)會(huì)執(zhí)行初始化塊 // Class.forName("zhongqiu.test.Test"); // 使用Class.forName()來(lái)加載類(lèi),并指定ClassLoader,初始化時(shí)不執(zhí)行靜態(tài)塊 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包里有個(gè)ClassLoader類(lèi),ClassLoader 的基本目標(biāo)是對(duì)類(lèi)的請(qǐng)求提供服務(wù),按需動(dòng)態(tài)裝載類(lèi)和資源,只有當(dāng)一個(gè)類(lèi)要使用(使用new 關(guān)鍵字來(lái)實(shí)例化一個(gè)類(lèi))的時(shí)候,類(lèi)加載器才會(huì)加載這個(gè)類(lèi)并初始化。一個(gè)Java應(yīng)用程序可以使用不同類(lèi)型的類(lèi)加載器。例如Web Application Server中,Servlet的加載使用開(kāi)發(fā)商自定義的類(lèi)加載器, java.lang.String在使用JVM系統(tǒng)加載器,Bootstrap Class Loader,開(kāi)發(fā)商定義的其他類(lèi)則由AppClassLoader加載。在JVM里由類(lèi)名和類(lèi)加載器區(qū)別不同的Java類(lèi)型。因此,JVM允許我們使用不同的加載器加載相同namespace的java類(lèi),而實(shí)際上這些相同namespace的java類(lèi)可以是完全不同的類(lèi)。這種機(jī)制可以保證JDK自帶的java.lang.String是唯一的。
八、為什么要使用這種雙親委托模式呢?
因?yàn)檫@樣可以避免重復(fù)加載,當(dāng)父親已經(jīng)加載了該類(lèi)的時(shí)候,就沒(méi)有必要子ClassLoader再加載一次。
考慮到安全因素,我們?cè)囅胍幌拢绻皇褂眠@種委托模式,那我們就可以隨時(shí)使用自定義的String來(lái)動(dòng)態(tài)替代java核心api中定義類(lèi)型,這樣會(huì)存在非常大的安全隱患,而雙親委托的方式,就可以避免這種情況,因?yàn)镾tring已經(jīng)在啟動(dòng)時(shí)被加載,所以用戶(hù)自定義類(lèi)是無(wú)法加載一個(gè)自定義的ClassLoader。
以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,同時(shí)也希望多多支持腳本之家!
相關(guān)文章
Java、C++中子類(lèi)對(duì)父類(lèi)函數(shù)覆蓋的可訪(fǎng)問(wèn)性縮小的區(qū)別介紹
這篇文章主要給大家介紹了關(guān)于Java、C++中子類(lèi)對(duì)父類(lèi)函數(shù)覆蓋的可訪(fǎng)問(wèn)性縮小的區(qū)別的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2018-01-01使用JPA單項(xiàng)一對(duì)多外鍵關(guān)聯(lián)
這篇文章主要介紹了使用JPA單項(xiàng)一對(duì)多外鍵關(guān)聯(lián),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06IntelliJ IDEA使用maven實(shí)現(xiàn)tomcat的熱部署
這篇文章主要介紹了IntelliJ IDEA使用maven實(shí)現(xiàn)tomcat的熱部署,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-07-07Spring的初始化和XML解析的實(shí)現(xiàn)
這篇文章主要介紹了Spring的初始化和XML解析的實(shí)現(xiàn),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-03-03