1. 類加載器
類加載器:實(shí)現(xiàn)這個(gè)動(dòng)作(通過一個(gè)類的全限定名來獲取描述此類的二進(jìn)制字節(jié)流)的代碼模塊被稱為"類加載器"
類加載器不僅僅只用于實(shí)現(xiàn)類的加載動(dòng)作,它還與類的相等判定有關(guān)。
判斷類相等,有三個(gè)條件:
- 兩個(gè)類來自同一個(gè)Class文件
- 兩個(gè)類是由同一個(gè)虛擬機(jī)加載
- 兩個(gè)類都是同一個(gè)類加載器加載
public class ClassLoaderTest {
public static void main(String[] args) throws Exception{
ClassLoader myLoder = new ClassLoader() {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
try {
String fileName = name.substring(name.lastIndexOf(".")) + ".class";
InputStream is = getClass().getResourceAsStream(fileName);
if (is == null){
return super.loadClass(name);
}
byte[] b = new byte[is.available()];
is.read(b);
return defineClass(name,b,0,b.length);
}catch (IOException e){
throw new ClassNotFoundException(name);
}
}
};
// 通過重寫loadClass方法,實(shí)現(xiàn)自己的加載器。結(jié)果發(fā)現(xiàn)出現(xiàn)了兩個(gè)ClassLoaderTest類,
// 原因就是一個(gè)是系統(tǒng)類加載器加載的,另外一個(gè)則是由我們實(shí)現(xiàn)的類加載器加載。
Object obj = myLoder.loadClass("classloader.ClassLoaderTest").newInstance();
System.out.println(obj.getClass()); // class classloader.ClassLoaderTest
System.out.println(obj instanceof classloader.ClassLoaderTest); // false
}
}
JVM在運(yùn)行時(shí)產(chǎn)生三個(gè)ClassLoader:
-
Bootstrap ClassLoader: 啟動(dòng)類加載器,也叫根加載器。負(fù)責(zé)加載<JAVA_HOME>\lib目錄中的類庫,也就是Java核心類。由C++實(shí)現(xiàn),無法被Java程序直接引用。 -
Extension ClassLoader擴(kuò)展類加載器,負(fù)責(zé)加載<JAVA_HOME>\lib\ext目錄中的類庫,用戶可以將自己開發(fā)的類打包成jar包放在這個(gè)目錄,即可擴(kuò)展核心類以外的新功能。 - System ClassLoader \ App ClassLoader: 系統(tǒng)類加載器或稱為應(yīng)用程序加載器,一般情況下是程序中默認(rèn)的類加載器。負(fù)責(zé)加載用戶類路徑(ClassPath)上所指定的類庫。
2. 雙親委派機(jī)制
當(dāng)一個(gè)類加載器收到了類加載的請(qǐng)求,它首先不會(huì)自己去嘗試加載這個(gè)類,而是把這個(gè)請(qǐng)求委派給父類加載器去完成,每一個(gè)層次的類加載器都是如此,因此所有的加載請(qǐng)求最終都應(yīng)該傳送到頂層的啟動(dòng)類加載器中,只有當(dāng)父類加載器無法完成這個(gè)加載請(qǐng)求時(shí),子類加載器才會(huì)嘗試去自己加載。
類加載器之間的父子關(guān)系是采用組合關(guān)系來復(fù)用父加載器的代碼。
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
protected synchronized Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// 首先,檢查請(qǐng)求的類是否已經(jīng)被加載過了
Class c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// 如果父類加載器拋出 ClassNotFoundException
// 則說明父類加載器無法完成加載請(qǐng)求
}
if (c == null) {
// 在父類加載器無法加載的時(shí)候
// 再調(diào)用本身的findClass方法來進(jìn)行類加載
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
使用雙親委派機(jī)制,保證了無論哪一個(gè)類加載器要加載這個(gè)類,最終都是委派給啟動(dòng)類加載器進(jìn)行加載,因此保證了類的唯一性。
3. 全盤負(fù)責(zé)
全盤負(fù)責(zé)是指 當(dāng)一個(gè)ClassLoader裝載一個(gè)類時(shí),除非顯示的使用另一個(gè)ClassLoader,則該類所依賴及引用的類也由這個(gè)ClassLoader載入。