常用的類加載器:
- Bootstrap ClassLoader
- Extension ClassLoader
- ApplicationClassLoader。
(1)類和類加載器
類加載器擁有自己獨(dú)立的命名空間,兩個(gè)類是否相等(instanceof),只有在這兩個(gè)類是同一個(gè)類加載器加載的才有意義。
(2)雙親委派模型
從Java虛擬機(jī)的角度來(lái)說(shuō),只存在兩種不同的類加載器:一種是啟動(dòng)類加載器(Bootstrap ClassLoader),這個(gè)類加載器使用C++語(yǔ)言實(shí)現(xiàn)(HotSpot虛擬機(jī)中),是虛擬機(jī)自身的一部分;另一種就是所有其他的類加載器,這些類加載器都有Java語(yǔ)言實(shí)現(xiàn),獨(dú)立于虛擬機(jī)外部,并且全部繼承自抽象類java.lang.ClassLoader。
從開(kāi)發(fā)者的角度,類加載器可以細(xì)分為:
? 啟動(dòng)(Bootstrap)類加載器:負(fù)責(zé)將 Java_Home/lib下面的類庫(kù)加載到內(nèi)存中(比如rt.jar)。由于引導(dǎo)類加載器涉及到虛擬機(jī)本地實(shí)現(xiàn)細(xì)節(jié),開(kāi)發(fā)者無(wú)法直接獲取到啟動(dòng)類加載器的引用,所以不允許直接通過(guò)引用進(jìn)行操作。
? 標(biāo)準(zhǔn)擴(kuò)展(Extension)類加載器:是由 Sun 的 ExtClassLoader(sun.misc.Launcher$ExtClassLoader)實(shí)現(xiàn)的。它負(fù)責(zé)將Java_Home /lib/ext或者由系統(tǒng)變量 java.ext.dir指定位置中的類庫(kù)加載到內(nèi)存中。開(kāi)發(fā)者可以直接使用標(biāo)準(zhǔn)擴(kuò)展類加載器。
? 應(yīng)用程序(Application)類加載器:是由 Sun 的 AppClassLoader(sun.misc.Launcher$AppClassLoader)實(shí)現(xiàn)的。它負(fù)責(zé)將系統(tǒng)類路徑(CLASSPATH)中指定的類庫(kù)加載到內(nèi)存中。開(kāi)發(fā)者可以直接使用系統(tǒng)類加載器。由于這個(gè)類加載器是ClassLoader中的getSystemClassLoader()方法的返回值,因此一般稱為系統(tǒng)(System)加載器。
除此之外,還有自定義的類加載器,它們之間的層次關(guān)系被稱為類加載器的雙親委派模型。該模型要求除了頂層的啟動(dòng)類加載器外,其余的類加載器都應(yīng)該有自己的父類加載器,而這種父子關(guān)系一般通過(guò)組合(Composition)關(guān)系來(lái)實(shí)現(xiàn),而不是通過(guò)繼承(Inheritance)。
雙親委派模型:
某個(gè)特定的類加載器在接到加載類的請(qǐng)求時(shí),首先將加載任務(wù)委托給父類加載器,依次遞歸,如果父類加載器可以完成類加載任務(wù),就成功返回;只有父類加載器無(wú)法完成此加載任務(wù)時(shí),才自己去加載。這一點(diǎn)是從安全角度考慮的,試想如果有人編寫了一個(gè)惡意的基礎(chǔ)類(如java.lang.String)并裝載到JVM中將會(huì)引起多么可怕的后果。但是由于有了“全盤負(fù)責(zé)委托機(jī)制”,java.lang.String永遠(yuǎn)是由根裝載器來(lái)裝載的,這樣就避免了上述事件的發(fā)生。
雙親委派模型的實(shí)現(xiàn):
很簡(jiǎn)單,全在loadClass中實(shí)現(xiàn),在java.lang.ClassLoader的loadClass()方法中,先檢查是否已經(jīng)被加載過(guò),若沒(méi)有加載則調(diào)用父類加載器的loadClass()方法,若父加載器為空則默認(rèn)使用啟動(dòng)類加載器作為父加載器。如果父加載失敗,則拋出ClassNotFoundException異常后,再調(diào)用自己的findClass()方法進(jìn)行加載。
protected synchronized Class<?> loadClass(String name,boolean resolve)throws ClassNotFoundException{
//check the class has been loaded or not
Class c = findLoadedClass(name);
if(c == null){
try{
if(parent != null){
c = parent.loadClass(name,false);
}else{
c = findBootstrapClassOrNull(name);
}
}catch(ClassNotFoundException e){
//if throws the exception ,the father can not complete the load
}
if(c == null){
c = findClass(name);
}
}
if(resolve){
resolveClass(c);
}
return c;
}
雙親委派模型打破:
重寫loadClass方法。