文章摘抄至 http://longdick.iteye.com/blog/442213/
?
要深入了解ClassLoader,首先就要知道ClassLoader是用來(lái)干什么的,顧名思義,它就是用來(lái)加載Class文件到JVM,以供程序使用的。我們知道,java程序可以動(dòng)態(tài)加載類定義,而這個(gè)動(dòng)態(tài)加載的機(jī)制就是通過(guò)ClassLoader來(lái)實(shí)現(xiàn)的,所以可想而知ClassLoader的重要性如何。?
?
看到這里,可能有的朋友會(huì)想到一個(gè)問(wèn)題,那就是既然ClassLoader是用來(lái)加載類到JVM中的,那么ClassLoader又是如何被加載呢?難道它不是java的類??
?
沒(méi)有錯(cuò),在這里確實(shí)有一個(gè)ClassLoader不是用java語(yǔ)言所編寫的,而是JVM實(shí)現(xiàn)的一部分,這個(gè)ClassLoader就是bootstrap classloader(啟動(dòng)類加載器),這個(gè)ClassLoader在JVM運(yùn)行的時(shí)候加載java核心的API以滿足java程序最基本的需求,其中就包括用戶定義的ClassLoader,這里所謂的用戶定義是指通過(guò)java程序?qū)崿F(xiàn)的ClassLoader,一個(gè)是ExtClassLoader,這個(gè)ClassLoader是用來(lái)加載java的擴(kuò)展API的,也就是/lib/ext中的類,一個(gè)是AppClassLoader,這個(gè)ClassLoader是用來(lái)加載用戶機(jī)器上CLASSPATH設(shè)置目錄中的Class的,通常在沒(méi)有指定ClassLoader的情況下,程序員自定義的類就由該ClassLoader進(jìn)行加載。?
?
當(dāng)運(yùn)行一個(gè)程序的時(shí)候,JVM啟動(dòng),運(yùn)行bootstrap classloader,該ClassLoader加載java核心API(ExtClassLoader和AppClassLoader也在此時(shí)被加載),然后調(diào)用ExtClassLoader加載擴(kuò)展API,最后AppClassLoader加載CLASSPATH目錄下定義的Class,這就是一個(gè)程序最基本的加載流程
?
java應(yīng)用環(huán)境中不同的class分別由不同的ClassLoader負(fù)責(zé)加載。
一個(gè)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擴(kuò)展類,主要是 %JRE_HOME/lib/ext 目錄下的jar和class
- App ClassLoader???? ?????? 負(fù)責(zé)加載當(dāng)前java應(yīng)用的classpath中的所有類。
其中Bootstrap ClassLoader是JVM級(jí)別的,由C++撰寫;Extension ClassLoader、App ClassLoader都是java類,都繼承自URLClassLoader超類。
Bootstrap ClassLoader由JVM啟動(dòng),然后初始化sun.misc.Launcher ,sun.misc.Launcher初始化Extension ClassLoader、App ClassLoader。
下圖是ClassLoader的加載類流程圖,以加載一個(gè)類的過(guò)程類示例說(shuō)明整個(gè)ClassLoader的過(guò)程。
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 擴(kuò)展類加載器
*/
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)系,只是語(yǔ)義上的定義,基本上,每一個(gè)ClassLoader實(shí)現(xiàn),都有一個(gè)Parent ClassLoader。
?
可以通過(guò)ClassLoader的getParent方法得到當(dāng)前ClassLoader的parent。Bootstrap ClassLoader比較特殊,因?yàn)樗皇莏ava class所以Extension ClassLoader的getParent方法返回的是NULL。
?
當(dāng)使用ClassLoader類的loadClass()方法來(lái)加載某個(gè)類時(shí),該方法只是加載該類,并不會(huì)執(zhí)行該類的初始化。使用Class的forName()靜態(tài)方法才會(huì)導(dǎo)致強(qiáng)制初始化該類。
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();
//不會(huì)執(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();
//不會(huì)執(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號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元

