類加載器的作用:
- 類加載,
通過(guò)類的權(quán)限定名獲取此類的二進(jìn)制字節(jié)流 - 確定被加載的類在jvm中的唯一性
兩個(gè)類是否相等的依據(jù):是否由同一個(gè)ClassLoader加載
兩個(gè)類是否相等的判斷:
- equals
- isAssignableFrom
- isInstance
類加載器的類型:
- 啟動(dòng)類加載器(Bootstrap ClassLoader)
- 用于加載存放在
<JAVA_HOME>\lib目錄下和被-Xbootclasspath參數(shù)指定的類(事先定義好的類) - 僅按文件名識(shí)別,如:rt.jar,名字不符合的類庫(kù)即使放在lib目錄中也不會(huì)被加載
- 無(wú)法被java程序直接使用
- 擴(kuò)展類加載器(Extension ClassLoader)
- 加載
JAVA_HOME>\lib\ext目錄中和被java.ext.dirs系統(tǒng)變量所指定的路徑中的類 - 開發(fā)者可以直接使用擴(kuò)展類加載器
- 應(yīng)用程序類加載器
- 負(fù)責(zé)加載 用戶類路徑
(ClassPath)上所指定的類庫(kù) - 該類加載器是
ClassLoader中的getSystemClassLoader()方法的返回值
雙親委派模型
雙親委派模型
注意點(diǎn):
- 除了頂層的啟動(dòng)類加載器,所有的加載器都有父類加載器
- 加載器之前的關(guān)系是組合關(guān)系來(lái)復(fù)用父類加載器的代碼,不是繼承
雙親委派模型的工作流程代碼實(shí)現(xiàn)在java.lang.ClassLoader的loadClass()
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException {
Class<?> c = findLoadedClass(name);
// 檢查需要加載的類是否已經(jīng)被加載過(guò)
if (c == null) {
try {
// 若沒(méi)有加載,則調(diào)用父加載器的loadClass()方法
if (parent != null) {
c = parent.loadClass(name, false);
}else{
// 若父類加載器為空,則默認(rèn)使用啟動(dòng)類加載器作為父加載器
c=findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// 若父類加載器加載失敗會(huì)拋出ClassNotFoundException,
//說(shuō)明父類加載器無(wú)法完成加載請(qǐng)求
}
if(c==null){
// 在父類加載器無(wú)法加載時(shí)
// 再調(diào)用本身的findClass方法進(jìn)行類加載
c=findClass(name);
}
}
if(resolve){
resolveClass(c);
}
return c;
}
加載流程:
- 當(dāng)一個(gè)加載器收到加載請(qǐng)求需求時(shí),會(huì)提交給他的父類加載器去完成
- 只有當(dāng)父類加載器反饋無(wú)法加載時(shí),自己才會(huì)去加載
優(yōu)點(diǎn):
類加載器的層級(jí)關(guān)系保證了java類的帶優(yōu)先級(jí)的層次關(guān)系:
- Object類只有啟動(dòng)類加載器會(huì)加載,所以只會(huì)有一個(gè)Object類,如果沒(méi)有雙親委派模型,多個(gè)類加載加載Object類會(huì)出現(xiàn)多個(gè)Object類,無(wú)法保證java的最基礎(chǔ)行為;
安卓的類加載器
-
BootClassLoader:加載framework中的類,如Activity.class -
PathClassLoader:加載項(xiàng)目中的類,如MainActivity.class,其父加載器是BootClassLoader -
DexClassLoader:加載指定目錄的類,其父加載器也是BootClassLoader -
InMemoryClassLoader:加載內(nèi)存中的類,不如字節(jié)數(shù)組(類似動(dòng)態(tài)代理中的那個(gè)東西)
類加載器加載類的原理:
BaseDexClassLoader:
private final DexPathList pathList;
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
...
Class c = pathList.findClass(name, suppressedExceptions);
...
}
DexPathList:
private Element[] dexElements;
public Class<?> findClass(String name, List<Throwable> suppressed) {
for (Element element : dexElements) {
Class<?> clazz = element.findClass(name, definingContext, suppressed);
if (clazz != null) {
return clazz;
}
}
return null;
}
private static Element[] makeDexElements(List<File> files, File optimizedDirectory,
List<IOException> suppressedExceptions, ClassLoader loader, boolean isTrusted) {
Element[] elements = new Element[files.size()];
int elementsPos = 0;
/*
* Open all files and load the (direct or contained) dex files up front.
*/
for (File file : files) {
if (file.isDirectory()) {
// We support directories for looking up resources. Looking up resources in
// directories is useful for running libcore tests.
elements[elementsPos++] = new Element(file);
} else if (file.isFile()) {
String name = file.getName();
DexFile dex = null;
if (name.endsWith(DEX_SUFFIX)) {
// Raw dex file (not inside a zip/jar).
try {
dex = loadDexFile(file, optimizedDirectory, loader, elements);
if (dex != null) {
elements[elementsPos++] = new Element(dex, null);
}
} catch (IOException suppressed) {
System.logE("Unable to load dex file: " + file, suppressed);
suppressedExceptions.add(suppressed);
}
} else {
try {
dex = loadDexFile(file, optimizedDirectory, loader, elements);
} catch (IOException suppressed) {
/*
* IOException might get thrown "legitimately" by the DexFile constructor if
* the zip file turns out to be resource-only (that is, no classes.dex file
* in it).
* Let dex == null and hang on to the exception to add to the tea-leaves for
* when findClass returns null.
*/
suppressedExceptions.add(suppressed);
}
if (dex == null) {
elements[elementsPos++] = new Element(file);
} else {
elements[elementsPos++] = new Element(dex, file);
}
}
if (dex != null && isTrusted) {
dex.setTrusted();
}
} else {
System.logW("ClassLoader referenced unknown path: " + file);
}
}
if (elementsPos != elements.length) {
elements = Arrays.copyOf(elements, elementsPos);
}
return elements;
}
private static DexFile loadDexFile(File file, File optimizedDirectory, ClassLoader loader,
Element[] elements)
throws IOException {
if (optimizedDirectory == null) {
return new DexFile(file, loader, elements);
} else {
String optimizedPath = optimizedPathFor(file, optimizedDirectory);
return DexFile.loadDex(file.getPath(), optimizedPath, 0, loader, elements);
}
}
Element: DexPathList的一個(gè)靜態(tài)內(nèi)部類
private final DexFile dexFile;
public Class<?> findClass(String name, ClassLoader definingContext,
List<Throwable> suppressed) {
return dexFile != null ? dexFile.loadClassBinaryName(name, definingContext, suppressed)
: null;
}
dexFile.loadClassBinaryName()是一個(gè)native方法
