ClassLoader類(lèi)加載源碼解析
Java類(lèi)加載器
1、BootClassLoader: 用于加載Android Framework層class文件。
2、PathClassLoader: 用于Android應(yīng)用程序類(lèi)加載器。可以加載指定的dex,jar、zip、zpk中的classes.dex
3、DexClassLoader:加載指定的dex,以及jar、zip、apk中的classes.dex


源碼解析
1.ClassLoader中提供loadClass用于加載指定類(lèi)
//ClassLoader.java
public Class<?> loadClass(String name) throws ClassNotFoundException {
//該處調(diào)用了兩個(gè)參數(shù)的重載方法
return loadClass(name, false);
}
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
//先查一下該類(lèi)是否已經(jīng)加載過(guò)了
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
//雙親委托機(jī)制,先讓爸爸去找
if (parent != null) {
c = parent.loadClass(name, false);
} else {
//如果parent為null,則用BootClassLoader進(jìn)行加載
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
//如果都找不到就自己去找,此方法在子類(lèi)BaseDexClassLoader類(lèi)中有重寫(xiě)
c = findClass(name);
}
}
return c;
}
2.BaseDexClassLoader類(lèi)中對(duì)findClass有重寫(xiě),也是實(shí)際會(huì)使用執(zhí)行的
//BaseDexClassLoader.java
//查找class
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
...
//這里通過(guò)pathList變量來(lái)查找,而pathList是在BaseDexClassLoader的構(gòu)造方法中初始化的
Class c = pathList.findClass(name, suppressedExceptions);
...
return c;
}
private final DexPathList pathList;
public BaseDexClassLoader(String dexPath, File optimizedDirectory,
String librarySearchPath, ClassLoader parent, boolean isTrusted) {
super(parent);
//構(gòu)造方法中初始化pathList變量
this.pathList = new DexPathList(this, dexPath, librarySearchPath, null, isTrusted);
}
3.BaseDexClassLoader中是通過(guò)調(diào)用DexPathList中的findClass來(lái)實(shí)現(xiàn)的,那么接下來(lái)我們分析一下DexPathList是怎么實(shí)現(xiàn)的
//DexPathList.java
//是一個(gè)Element數(shù)組,一個(gè)element中包含一個(gè) DexFile,DexFile就代表一個(gè)Dex文件,里面的native(C/C++)函數(shù)來(lái)進(jìn)行Dex的加載工作
private Element[] dexElements;
public Class<?> findClass(String name, List<Throwable> suppressed) {
for (Element element : dexElements) {
//此處調(diào)用Element的findClass來(lái)實(shí)現(xiàn),
Class<?> clazz = element.findClass(name, definingContext, suppressed);
if (clazz != null) {
return clazz;
}
}
return null;
}
// Element為DexPathList的內(nèi)部類(lèi)
static class Element {
private final File path;
//一個(gè)DexFile就代表一個(gè)Dex文件
private final DexFile dexFile;
//有多個(gè)構(gòu)造方法,但都僅是將值傳過(guò)來(lái),讓Element來(lái)持有一個(gè)DexFile
public Element(DexFile dexFile) {
this.dexFile = dexFile;
this.path = null;
}
public Class<?> findClass(String name, ClassLoader definingContext,
List<Throwable> suppressed) {
//通過(guò)DexFile來(lái)加載類(lèi)
return dexFile != null ? dexFile.loadClassBinaryName(name, definingContext, suppressed)
: null;
}
}
DexPathList(ClassLoader definingContext, String dexPath,
String librarySearchPath, File optimizedDirectory, boolean isTrusted) {
//通過(guò)makeDexElements方法為dexElements初始化
this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,
suppressedExceptions, definingContext, isTrusted);
}
//騰訊系的熱修復(fù),諸如微信tinker、qq空間qfix原理便是反射此方法,將修復(fù)后的類(lèi)打包成dex,通過(guò)反射該方法來(lái)將文件轉(zhuǎn)化為Element,并將新生成的element放到dexElements前面,這樣下次系統(tǒng)再去尋找某個(gè)class時(shí),會(huì)先從修復(fù)后的dex中來(lái)找class,找到后便不再繼續(xù)查找,從而修復(fù)該class,此方式便為插樁
private static Element[] makeDexElements(List<File> files, File optimizedDirectory,
List<IOException> suppressedExceptions, ClassLoader loader, boolean isTrusted) {
Element[] elements = new Element[files.size()];
...
for (File file : files) {
if (name.endsWith(DEX_SUFFIX)) {
//以 .dex 結(jié)尾的
// Raw dex file (not inside a zip/jar).
//加載dex文件
dex = loadDexFile(file, optimizedDirectory, loader, elements);
if (dex != null) {
elements[elementsPos++] = new Element(dex, null);
}
}
}
...
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);
}
}
4.這里通過(guò) new DexFile 或者 loadDex方法來(lái)創(chuàng)建DexFile,兩者類(lèi)似,那我們拿new DexFile 來(lái)舉例分析
//DexFile.java
private DexFile(String sourceName, String outputName, int flags, ClassLoader loader,
DexPathList.Element[] elements) throws IOException {
...
//此處調(diào)用openDexFile來(lái)實(shí)現(xiàn)
mCookie = openDexFile(sourceName, outputName, flags, loader, elements);
...
}
private static Object openDexFile(String sourceName, String outputName, int flags,
ClassLoader loader, DexPathList.Element[] elements) throws IOException {
//此處通過(guò)調(diào)用 openDexFileNative來(lái)實(shí)現(xiàn)
return openDexFileNative(new File(sourceName).getAbsolutePath(),
(outputName == null)
? null
: new File(outputName).getAbsolutePath(),
flags,
loader,
elements);
}
//openDexFileNative是一個(gè)native方法,是由C/C++來(lái)實(shí)現(xiàn)的
private static native Object openDexFileNative(String sourceName, String outputName, int flags,
ClassLoader loader, DexPathList.Element[] elements);
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- jvm之java類(lèi)加載機(jī)制和類(lèi)加載器(ClassLoader)的用法
- Java類(lèi)加載器ClassLoader用法解析
- Java運(yùn)行時(shí)環(huán)境之ClassLoader類(lèi)加載機(jī)制詳解
- 深入Spring Boot之ClassLoader的繼承關(guān)系和影響
- 關(guān)于Android中自定義ClassLoader耗時(shí)問(wèn)題的追查
- 淺談Android Classloader動(dòng)態(tài)加載分析
- Java Classloader機(jī)制用法代碼解析
- Java中ClassLoader類(lèi)加載學(xué)習(xí)總結(jié)
- 詳解Android類(lèi)加載ClassLoader
- 如何理解和運(yùn)用ClassLoader
相關(guān)文章
Java實(shí)現(xiàn)文件檢索系統(tǒng)的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何劉Java語(yǔ)言實(shí)現(xiàn)簡(jiǎn)易的文件檢索系統(tǒng),文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Java開(kāi)發(fā)有一定的幫助,需要的可以參考一下2022-07-07
Apache Commons Math3探索之多項(xiàng)式曲線(xiàn)擬合實(shí)現(xiàn)代碼
這篇文章主要介紹了Apache Commons Math3探索之多項(xiàng)式曲線(xiàn)擬合實(shí)現(xiàn)代碼,小編覺(jué)得挺不錯(cuò)的,這里分享給大家,供需要的朋友參考。2017-10-10
Springboot設(shè)置默認(rèn)訪(fǎng)問(wèn)路徑方法實(shí)現(xiàn)
這篇文章主要介紹了Springboot設(shè)置默認(rèn)訪(fǎng)問(wèn)路徑方法實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
關(guān)于BufferedReader讀取文件指定字符集問(wèn)題
這篇文章主要介紹了關(guān)于BufferedReader讀取文件指定字符集問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
解決SpringBoot application.yaml文件配置schema 無(wú)法執(zhí)行sql問(wèn)題
這篇文章主要介紹了解決SpringBoot application.yaml文件配置schema 無(wú)法執(zhí)行sql問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08
解決Java項(xiàng)目啟動(dòng)報(bào)錯(cuò):Logback?configuration?error?detected:問(wèn)題
這篇文章主要介紹了解決Java項(xiàng)目啟動(dòng)報(bào)錯(cuò):Logback?configuration?error?detected:問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04
java中實(shí)現(xiàn)excel合并單元格詳細(xì)代碼實(shí)例
最近的工作中,遇到一個(gè)需求在生成的Excel表格后需要在尾部添加一個(gè)合并的單元格數(shù)據(jù),這篇文章主要給大家介紹了關(guān)于java中實(shí)現(xiàn)excel合并單元格的相關(guān)資料,需要的朋友可以參考下2024-06-06

