本文学习的源码参考AndroidXRef,版本为Lollipop 5.1.0_r1。
类加载与动态加载
Java代码是通过Class来实现的,程序运行时虚拟机首先将对应的类加载到内存中,然后才能进行对象实例化以及后续工作,而这个加载过程就是通过ClassLoader来实现的,也即是类加载。
同时,在Java虚拟机中,我们可以自定义继承自ClassLoader的类加载器,通过defineClass方法动态加载一个Class,实现控制程序的类加载过程,提高程序的灵活性。
Android的Dalvik/ART虚拟机与Java虚拟机一样,采用类加载机制,也具有动态加载技术,但是他们之间还是存在一些差异的。
Android的类加载机制
不管是类加载还是动态加载,它的基础都是ClassLoader,也即专门用来处理类加载工作的,也称为类加载器。而且,一个应用不仅仅只有一个类加载器。
实际上,Android系统启动时,会创建一个Boot类型的ClassLoader实例,用于加载一些系统Framework层级需要的类,而Android应用里也需要用到一些系统的类,所以APP启动的时候也会把这个Boot类型的ClassLoader传进来。另外,APP也有自己实现的类,这些类保存在APK的dex文件里面,所以APP启动的时候,也会创建一个自己的ClassLoader实例,用于加载自己dex文件中的类。
可以通过下面的代码查看当前程序的类加载器:
// 获取当前程序的类加载器
ClassLoader classLoader = getClassLoader();
if (classLoader != null){
Log.i(TAG, "[onCreate] classLoader " + i + " : " + classLoader.toString());
// 获取当前类加载器的父类加载器
while (classLoader.getParent()!=null){
classLoader = classLoader.getParent();
Log.i(TAG,"[onCreate] classLoader " + i + " : " + classLoader.toString());
}
}
Android中的ClassLoader是一个抽象类,实际开发过程中,我们一般是使用他的两个具体的子类DexClassLoader、PathClassLoader这些类加载器来加载类的。他们的主要差别在于:
- PathClassLoader只能加载系统中已经安装过的apk;
- DexClassLoader可以加载jar/apk/dex,可以从SD卡中加载未安装的apk;
看具体代码:
public class PathClassLoader extends BaseDexClassLoader {
public PathClassLoader(String dexPath, ClassLoader parent) {
super(dexPath, null, null, parent);
}
public PathCla