這篇文章主要介紹了ClassLoader類加載的示例分析,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
Java類加載器
1、BootClassLoader: 用于加載Android Framework層class文件。
2、PathClassLoader: 用于Android應用程序類加載器??梢约虞d指定的dex,jar、zip、zpk中的classes.dex
3、DexClassLoader:加載指定的dex,以及jar、zip、apk中的classes.dex


源碼解析
1.ClassLoader中提供loadClass用于加載指定類
//ClassLoader.java
public Class<?> loadClass(String name) throws ClassNotFoundException {
//該處調用了兩個參數的重載方法
return loadClass(name, false);
}
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
//先查一下該類是否已經加載過了
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
//雙親委托機制,先讓爸爸去找
if (parent != null) {
c = parent.loadClass(name, false);
} else {
//如果parent為null,則用BootClassLoader進行加載
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
//如果都找不到就自己去找,此方法在子類BaseDexClassLoader類中有重寫
c = findClass(name);
}
}
return c;
}2.BaseDexClassLoader類中對findClass有重寫,也是實際會使用執行的
//BaseDexClassLoader.java
//查找class
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
...
//這里通過pathList變量來查找,而pathList是在BaseDexClassLoader的構造方法中初始化的
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);
//構造方法中初始化pathList變量
this.pathList = new DexPathList(this, dexPath, librarySearchPath, null, isTrusted);
}3.BaseDexClassLoader中是通過調用DexPathList中的findClass來實現的,那么接下來我們分析一下DexPathList是怎么實現的
//DexPathList.java
//是一個Element數組,一個element中包含一個 DexFile,DexFile就代表一個Dex文件,里面的native(C/C++)函數來進行Dex的加載工作
private Element[] dexElements;
public Class<?> findClass(String name, List<Throwable> suppressed) {
for (Element element : dexElements) {
//此處調用Element的findClass來實現,
Class<?> clazz = element.findClass(name, definingContext, suppressed);
if (clazz != null) {
return clazz;
}
}
return null;
}
// Element為DexPathList的內部類
static class Element {
private final File path;
//一個DexFile就代表一個Dex文件
private final DexFile dexFile;
//有多個構造方法,但都僅是將值傳過來,讓Element來持有一個DexFile
public Element(DexFile dexFile) {
this.dexFile = dexFile;
this.path = null;
}
public Class<?> findClass(String name, ClassLoader definingContext,
List<Throwable> suppressed) {
//通過DexFile來加載類
return dexFile != null ? dexFile.loadClassBinaryName(name, definingContext, suppressed)
: null;
}
}
DexPathList(ClassLoader definingContext, String dexPath,
String librarySearchPath, File optimizedDirectory, boolean isTrusted) {
//通過makeDexElements方法為dexElements初始化
this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,
suppressedExceptions, definingContext, isTrusted);
}
//騰訊系的熱修復,諸如微信tinker、qq空間qfix原理便是反射此方法,將修復后的類打包成dex,通過反射該方法來將文件轉化為Element,并將新生成的element放到dexElements前面,這樣下次系統再去尋找某個class時,會先從修復后的dex中來找class,找到后便不再繼續查找,從而修復該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 結尾的
// 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.這里通過 new DexFile 或者 loadDex方法來創建DexFile,兩者類似,那我們拿new DexFile 來舉例分析
//DexFile.java
private DexFile(String sourceName, String outputName, int flags, ClassLoader loader,
DexPathList.Element[] elements) throws IOException {
...
//此處調用openDexFile來實現
mCookie = openDexFile(sourceName, outputName, flags, loader, elements);
...
}
private static Object openDexFile(String sourceName, String outputName, int flags,
ClassLoader loader, DexPathList.Element[] elements) throws IOException {
//此處通過調用 openDexFileNative來實現
return openDexFileNative(new File(sourceName).getAbsolutePath(),
(outputName == null)
? null
: new File(outputName).getAbsolutePath(),
flags,
loader,
elements);
}
//openDexFileNative是一個native方法,是由C/C++來實現的
private static native Object openDexFileNative(String sourceName, String outputName, int flags,
ClassLoader loader, DexPathList.Element[] elements);感謝你能夠認真閱讀完這篇文章,希望小編分享的“ClassLoader類加載的示例分析”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。