文章摘抄至 http://longdick.iteye.com/blog/442213/
?
要深入了解ClassLoader,首先就要知道ClassLoader是用來干什么的,顧名思義,它就是用來加載Class文件到JVM,以供程序使用的。我們知道,java程序可以動態(tài)加載類定義,而這個動態(tài)加載的機制就是通過ClassLoader來實現(xiàn)的,所以可想而知ClassLoader的重要性如何。?
?
看到這里,可能有的朋友會想到一個問題,那就是既然ClassLoader是用來加載類到JVM中的,那么ClassLoader又是如何被加載呢?難道它不是java的類??
?
沒有錯,在這里確實有一個ClassLoader不是用java語言所編寫的,而是JVM實現(xiàn)的一部分,這個ClassLoader就是bootstrap classloader(啟動類加載器),這個ClassLoader在JVM運行的時候加載java核心的API以滿足java程序最基本的需求,其中就包括用戶定義的ClassLoader,這里所謂的用戶定義是指通過java程序?qū)崿F(xiàn)的ClassLoader,一個是ExtClassLoader,這個ClassLoader是用來加載java的擴展API的,也就是/lib/ext中的類,一個是AppClassLoader,這個ClassLoader是用來加載用戶機器上CLASSPATH設(shè)置目錄中的Class的,通常在沒有指定ClassLoader的情況下,程序員自定義的類就由該ClassLoader進(jìn)行加載。?
?
當(dāng)運行一個程序的時候,JVM啟動,運行bootstrap classloader,該ClassLoader加載java核心API(ExtClassLoader和AppClassLoader也在此時被加載),然后調(diào)用ExtClassLoader加載擴展API,最后AppClassLoader加載CLASSPATH目錄下定義的Class,這就是一個程序最基本的加載流程
?
java應(yīng)用環(huán)境中不同的class分別由不同的ClassLoader負(fù)責(zé)加載。
一個jvm中默認(rèn)的classloader有Bootstrap ClassLoader、Extension ClassLoader、App ClassLoader,分別各司其職:
- Bootstrap ClassLoader?? ?? ?負(fù)責(zé)加載java基礎(chǔ)類,主要是 %JRE_HOME/lib/ 目錄下的rt.jar、resources.jar、charsets.jar和class等
- Extension ClassLoader?? ? ?? 負(fù)責(zé)加載java擴展類,主要是 %JRE_HOME/lib/ext 目錄下的jar和class
- App ClassLoader???? ?????? 負(fù)責(zé)加載當(dāng)前java應(yīng)用的classpath中的所有類。
其中Bootstrap ClassLoader是JVM級別的,由C++撰寫;Extension ClassLoader、App ClassLoader都是java類,都繼承自URLClassLoader超類。
Bootstrap ClassLoader由JVM啟動,然后初始化sun.misc.Launcher ,sun.misc.Launcher初始化Extension ClassLoader、App ClassLoader。
下圖是ClassLoader的加載類流程圖,以加載一個類的過程類示例說明整個ClassLoader的過程。
public class ClassLoaderTree { public static void main(String[] args) { ClassLoader loader = ClassLoaderTree.class.getClassLoader(); /** sun.misc.Launcher$AppClassLoader@39ab89 系統(tǒng)類加載器 sun.misc.Launcher$ExtClassLoader@2cb49d 擴展類加載器 */ while(loader != null){ System.out.println(loader.toString()); loader = loader.getParent(); } } }
Bootstrap ClassLoader、Extension ClassLoader、App ClassLoader三者的關(guān)系如下:
Bootstrap ClassLoader是Extension ClassLoader的parent,Extension ClassLoader是App ClassLoader的parent。但是這并不是繼承關(guān)系,只是語義上的定義,基本上,每一個ClassLoader實現(xiàn),都有一個Parent ClassLoader。
?
可以通過ClassLoader的getParent方法得到當(dāng)前ClassLoader的parent。Bootstrap ClassLoader比較特殊,因為它不是java class所以Extension ClassLoader的getParent方法返回的是NULL。
?
當(dāng)使用ClassLoader類的loadClass()方法來加載某個類時,該方法只是加載該類,并不會執(zhí)行該類的初始化。使用Class的forName()靜態(tài)方法才會導(dǎo)致強制初始化該類。
package hb.reflect; public class Tester{ static{ System.out.println("初始化塊"); } }
?
package hb.reflect; public class ClassLoaderTest { public static void main(String[] args) throws ClassNotFoundException { ClassLoader c1 = ClassLoader.getSystemClassLoader(); //不會執(zhí)行初始化 c1.loadClass("hb.reflect.Tester"); System.out.println("系統(tǒng)加載Tester類"); //執(zhí)行初始化內(nèi)容 Class.forName("hb.reflect.Tester"); } }
?打印內(nèi)容:
系統(tǒng)加載Tester類
初始化塊
?
如果將代碼如下修改:
package hb.classloader; public class ClassLoaderTest { public static void main(String[] args) throws ClassNotFoundException { ClassLoader c1 = ClassLoader.getSystemClassLoader(); //不會執(zhí)行初始化 Class clazz = c1.loadClass("hb.classloader.Tester"); // try { Tester tester = (Tester)clazz.newInstance(); tester.print("class.newInstance() is ok"); } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } System.out.println("系統(tǒng)加載Tester類"); //執(zhí)行初始化內(nèi)容 Class.forName("hb.classloader.Tester"); } }
?打印結(jié)果:
初始化塊
class.newInstance() is ok
系統(tǒng)加載Tester類
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
