类加载机制
在安卓中提供了3个类加载器,BootClassLoader,PathClassLoader,DexClassLoader;双亲委派机制,是委培层级上的上下层级关系,并不是说3个类加载器有父子继承关系:
类加载的委派层级
BootClassLoader -> PathClassLoader -> DexClassLoader ;
类加载器的继承结构
BootClassLoader 是父类 , PathClassLoader / DexClassLoader 是 BootClassLoader 的子类 ;
① DexClassLoader 查询 :查询自己是否加载过 A ;
如果加载过则不需要再进行加载 ;
如果没有加载过 , 则向上级 PathClassLoader 询问 是否有加载过 A ;
② PathClassLoader 查询 :查询自己是否加载过 A ;
如果加载过则不需要再进行加载 ;
如果没有加载过 , 则向上级 BootClassLoader 询问 是否有加载过 A ;
③ BootClassLoader 查询 :查询自己是否加载过 A ;
如果加载过则不需要再进行加载 ;
如果没有加载过 , 则 查询自己是否可以加载 ;
④ BootClassLoader 查询是否可以加载 :
如果自己可以加载 A , 则自己加载 ;
如果自己不可以加载 A , 则将加载任务委派给下级 PathClassLoader ;
⑤ PathClassLoader 查询是否可以加载 :
如果自己可以加载 A , 则自己加载 ;
如果自己不可以加载 A , 则将加载任务 委派给下级 DexClassLoader ;
④ DexClassLoader 查询是否可以加载 :
如果自己可以加载 A , 则自己加载 ;
如果自己不可以加载 A , 则 抛出 Class Not Found 异常 ;
整个过程就是 从下到上 询问 , 然后 从上到下 委派 ;
双亲委派机制
类加载器层级
由高到低 : BootClassLoader -> PathClassLoader / DexClassLoader
什么是双亲委派
1.加载.class文件的时候,以递归的的形式逐级向上委托给父加载器ParentClassLoader去加载,如果加载过了,就不用在加载一遍2.如果父加载器也没加载过,则继续委托给父加载器去加载,一直到这条链路的顶级,顶级classLoader判断如果没加载过,则尝试加载,加载失败,则逐级向下交还调用者来加载.
双亲委派是如何实现的
任意一个classLoader对象都会有一个parent对象,我们下面的customClassLoader创建的时候虽然没有传递parent对象,但是在下面的ClassLoader类中的空参构造方法可以看出,会调用getSystemClassLoader()从而调用ClassLoader.createSystemClassLoader();,最后创建了一个PathClassLoader对象作为parent,而且在创建PathClassLoader的同时也指定了它的parent为BootClassLoader
ClassLoader customClassLoader= new ClassLoader() {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
return super.loadClass(name);
}
};
public abstract class ClassLoader {
static private class SystemClassLoader {
public static ClassLoader loader = ClassLoader.createSystemClassLoader();
}
protected ClassLoader() {
this(checkCreateClassLoader(), getSystemClassLoader());
}
protected ClassLoader(ClassLoader parent) {
this(checkCreateClassLoader(), parent);
}
@CallerSensitive
public static ClassLoader getSystemClassLoader() {
return SystemClassLoader.loader;
}
private static ClassLoader createSystemClassLoader() {
String classPath = System.getProperty("java.class.path", ".");
String librarySearchPath = System.getProperty("java.library.path", "");
//最终会调用PathClassLoader这个classLoader
return new PathClassLoader(classPath, librarySearchPath, BootClassLoader.getInstance());
}
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException{
//1.先检查是否已经加载过--findLoaded
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
//2.如果自己没加载过,存在父类,则委托父类
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
}
if (c == null) {
//3.如果父类也没加载过,则尝试本级classLoader加载
c = findClass(name);
}
}
return c;
}
}
loadClass方法,对于任意一个classLoader对象来说,来加载文件的时候都会调用loadClass方法.
1.先检查自己是否已经加载过class文件了--用这个findLoadedClass方法,如果已经加载了直接返回就好了2.如果自己没加载过,存在父类,则委托父类去加载--用这个parent.loadClass(name, false)方法,此时就会向上传递,然后就会去父加载器中循环第1步,一直到顶级ClassLoader3.如果父类也没加载过,则尝试本级classLoader加载,如果加载失败了就会向下传递,交给调用方来实现.class文件的加载
双亲委派的作用
1.防止同一个.class文件重复加载
2.对于任意一个类确保在虚拟机中的唯一性.由加载它的类加载器和这个类的全类名一同确立其在Java虚拟机中的唯一性
3.保证.class文件不被篡改,通过委托方式可以保证系统类的加载逻辑不被篡改.
Android中的主要类加载器
1.PathClassLoader复杂的加载系统类和英勇程序的类,通常用来加载已安装apk的dex文件,实际上外部存储的dex文件也能加载
2.DexClassLoader可以加载dex文件以及包含dex的压缩文件(apk,dex,jar,zip)
3.BaseDexClassLoader实际应用层类文件的加载,而真正的加载逻辑委托给pathList来完成
4.BootClassLoaderAndroid平台上所有ClassLoader的最终parent,Android系统启动时会使用BootClassLoader来预加载常用类