一、概述
上篇文章中概述了類(lèi)的加載流程,那么類(lèi)是由什么來(lái)加載的呢?毫無(wú)疑問(wèn)就是類(lèi)加載器,類(lèi)加載器是Java中很重要的概念,它負(fù)責(zé)將字節(jié)碼文件加載到Jvm虛擬機(jī)中。在Java中有三大類(lèi)加載器:?jiǎn)?dòng)類(lèi)加載器,擴(kuò)展類(lèi)加載器,應(yīng)用程序類(lèi)加載器。
二、啟動(dòng)類(lèi)加載器
啟動(dòng)類(lèi)加載器(Bootstrap ClassLoader)是由c/c++語(yǔ)言實(shí)現(xiàn)的,是JVM的一部分。
它用來(lái)加載Java的核心類(lèi)庫(kù):rt.jar,resources.jar或sun.boot.class.path下的內(nèi)容。
三、擴(kuò)展類(lèi)加載器
擴(kuò)展類(lèi)加載器(Extension ClassLoader)是由Java語(yǔ)言編寫(xiě),由sun.misc.Launcher$ExtClassLoader實(shí)現(xiàn)。
派生于ClassLoader類(lèi)。父類(lèi)加載器為啟動(dòng)類(lèi)加載器。
它用來(lái)加載Java_HOME/lib/ext中的類(lèi),以及 java.ext.dirs系統(tǒng)屬性所指定的目錄中的類(lèi)庫(kù)。
四、應(yīng)用程序類(lèi)加載器
應(yīng)用程序類(lèi)加載器(AppClassLoader)是由Java語(yǔ)言編寫(xiě),由sun.misc.Launcher$AppClassLoader實(shí)現(xiàn)。
派生于ClassLoader類(lèi),父類(lèi)加載器為擴(kuò)展類(lèi)加載器。
復(fù)雜加載環(huán)境變量中classpath或系統(tǒng)屬性java.class.path指定路徑下的類(lèi)庫(kù)。
應(yīng)用程序類(lèi)加載器是程序中默認(rèn)的類(lèi)加載器,一般Java應(yīng)用的類(lèi)都是由它完成加載。
public class Main {
public static void main(String[] args) {
ClassLoader loader = ClassLoader.getSystemClassLoader();
System.out.println(loader);
System.out.println(loader.getParent());
}
}
輸出:
sun.misc.Launcher$AppClassLoader@73d16e93
sun.misc.Launcher$ExtClassLoader@15db9742
五、雙親委派機(jī)制
- 如果一個(gè)類(lèi)加載器收到了類(lèi)加載的請(qǐng)求,他并不會(huì)自己去加載,而是把這個(gè)請(qǐng)求委托給父類(lèi)加載器。
- 如果父類(lèi)加載器還存在父類(lèi)加載器,則進(jìn)一步向上委托,直到請(qǐng)求達(dá)到最頂層的啟動(dòng)類(lèi)加載器。
- 如果父類(lèi)加載器可以完成類(lèi)的加載則返回,如果父類(lèi)加載器無(wú)法完成加載任務(wù),子加載器才會(huì)嘗試自己去加載。這就是雙親委派機(jī)制。
舉個(gè)例子:
假如我在項(xiàng)目目錄下創(chuàng)建一個(gè)java.lang的包,然后再創(chuàng)建一個(gè)String類(lèi),代碼如下:
package java.lang;
public class String {
static {
System.out.println("我是自定義的String");
}
}
然后我們來(lái)使用String:
class Test {
public static void main(String[] args) {
java.lang.String str = new java.lang.String();
System.out.println("Hello");
}
}
此時(shí)運(yùn)行,這個(gè)String到底是哪個(gè)String呢?自定義的String還是Java核心庫(kù)中的String呢?我們運(yùn)行看下輸出:
Hello
控制臺(tái)只輸出了Hello,而我們自定義的String中的靜態(tài)代碼塊并沒(méi)有執(zhí)行,說(shuō)明加載的是Java核心庫(kù)的String。
可以說(shuō)如果你自己創(chuàng)建了一個(gè)和Java庫(kù)中同名的類(lèi),那么你的類(lèi)永遠(yuǎn)得不到加載。
在這個(gè)例子中,如果Java使用Test的類(lèi)加載器即應(yīng)用程序加載器加載String,那么加載的就是我們自定義的String了,但是如果加載了自定義的String,萬(wàn)一你自定義的String有毒咋整?所以這就是為什么會(huì)有雙親委派機(jī)制。