这篇文章主要讲述Android内的Class加载机制,主要分为JAVA和Native的两部分。
一、ClassLoader
JAVA层的Class加载本质就是ClassLoader的内容,我们首先来看下类的关系吧。
DexClassLoader和PathClassLoader继承BaseDexClassLoader。BaseDexClassLoader关键的方法findClass(String name),根据类名加载Class,我们以这里作为入口来看看是怎么实现的。
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
Class c = pathList.findClass(name, suppressedExceptions);
if (c == null) {
ClassNotFoundException cnfe = new ClassNotFoundException("Didn't find class \"" + name + "\" on path: " + pathList);
for (Throwable t : suppressedExceptions) {
cnfe.addSuppressed(t);
}
throw cnfe;
}
return c;
}
这个函数通过pathList来查找类,这个pathList类型是DexPathList。
public Class findClass(String name, List<Throwable> suppressed) {
for (Element element : dexElements) {
DexFile dex = element.dexFile;
if (dex != null) {
Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed);
if (clazz != null) {
return clazz;
}
}
}
if (dexElementsSuppressedExceptions != null) {
suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));
}
return null;
}
DexPathList这个类是用来保存和ClassLoader相关的dex和resource加载路径资源的,它里面保存着一个Element数组
private final File file;
private final boolean isDirectory;
private final File zip;
private final DexFile dexFile;
从上面可以看到,Element可以存储普通文件,zip和DexFile,findClass的时候就是顺序去数组里面查看每一个Element里面的DexFile是否可以加载Class。 Element[]相关的信息是从DexPathList构造函数传入,然后通过makeDexElements来解析,makeDexElements的过程这里面不细讲,我们来看下DexPathList的构造函数
/**
* Constructs an instance.
*
* @param definingContext the context in which any as-yet unresolved
* classes should be defined
* @param dexPath list of dex/resource path elements, separated by
* {@code File.pathSeparator}
* @param libraryPath list of native library directory path elements,
* separated by {@code File.pathSeparator}
* @param optimizedDirectory directory where optimized {@code .dex} files
* should be found and written to, or {@code null} to use the default
* system directory for same
*/
public DexPathList(ClassLoader definingContext, String dexPath, String libraryPath, File optimizedDirectory)
可以看到一些lib和dex的信息就是从这里来的。好的,让我们来探讨下PathClassLoader和DexClassLoader的区别,
他们俩最大的区别在于构造函数的传参,体现在生成DexPathList的optimizedDirectory上面,DexClassLoader是可以传该变量的,而PathClassLoader没有,因此,DexPathList可以加载外部的dex文件,而PathClassLoader则不能。