1. Android中ClassLoader类图
- PathClassLoader是应用加载类,加载base.apk中的dex文件
- DexClassLoader在8.0以后,与PathClassLoader几乎没有区别
- android中类加载也是双亲委托模型,避免重复加载、保证安全性
双亲委托模型代码 ClassLoader#loadClass
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name);
}
}
return c;
}
2. Android中类加载时序图
类加载过程,最终是将dex文件解析存储到DexPathList对象的dexElements数组中;
findClass方法就是遍历Element []数组,找到并返回Class对象。
/*package*/ final class 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;
}
}
if (dexElementsSuppressedExceptions != null) {
suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));
}
return null;
}
...
}
3. 总结
- findLoadedClass() 遵循双亲委托模型;
- findClass() 是通过DexPathList.findClass()方法,遍历其内部属性Element[]数组,返回Class对象;
- Dex插桩热修复方案,就是将patch补丁包插入Element[]数组前面,来实现加载patch中class,达到热修复的目的(需要重启应用, 比如Qzone热修复)。