写点什么

Android 热修复基础篇(二),android 设计模式面试题

用户头像
Android架构
关注
发布于: 刚刚

appCompatClassLoader -> dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.wust.jingdutiao-jnlJr4sTotwg6ttws9yYFw==/base.apk"],nativeLibraryDirectories=[/data/app/com.wust.jingdutiao-jnlJr4sTotwg6ttws9yYFw==/lib/arm64, /system/lib64, /product/lib64]]]


I/System.out: activityClassLoader -> java.lang.BootClassLoader@9e062e4



运行结果分析:


  • BootClassLoader 类加载器是加载 Android 系统自带的 类,如 Activity

  • PathClassLoader 类加载器是加载 第三方类或自己写的类,(不是 Android 自带的),如 MainActivity、AppCompatActivity


补充点:现在你应该明白了,为什么你写的类直接调用就好了,这是因为 系统帮你选择好了 类加载器 自动帮你把需要的类加载进来,即类加载过程代码如下(系统自动替你完成了):


getClassLoader().loadClass() //在这里只是表明类加载逻辑,实际加载过程没这么简单


  • PathClassLoader 源码分析




源码展示


public class PathClassLoader extends BaseDexClassLoader {


public PathClassLoader(String dexPath, ClassLoader parent) {


super((String)null, (File)null, (String)null, (ClassLoader)null);


throw new RuntimeException("Stub!");


}


public PathClassLoader(String dexPath, String librarySearchPath, ClassLoader parent) {


super((String)null, (File)null, (String)null, (ClassLoader)null);


throw new RuntimeException("Stub!");


}


}


源码分析


  • 源码里面只包含两个构造方法

  • 构造方法中 ClassLoader parent 传的是 BootClassLoader


由于 PathClassLoader 源码太简单,没有找到我们想要的 loadClass() 方法,所以我们来看看其父类?BaseDexClassLoader,发现还是没有,继续找父类?ClassLoader,在这里面我们看到了 loadClass()


//发现了两个 是重载方法


public Class<?> loadClass(String name) throws ClassNotFoundException {


//可以看到 最后还是调到了 含两个参数的 loadClass 方法,


return loadClass(name, false);


}


protected Class<?> loadClass(String name, boolean resolve)


throws ClassNotFoundException


{


// First, check if the class has already been loaded


//找缓存


//1、在 Android 中 class 存在于 dex file 中


//2、public PathClassLoader(String dexPath, ClassLoader parent) 第一个参数就是就是 dex 文件的存放路径


//3、所以 classLoader 在加载类的时候 是通过 IO 操作将文件读进来 ,然后按照 dex 格式解析出每一个类!


//4、为了避免你重复用一个类的时候反复 IO 读取+解析 所以,先找缓存


Class<?> c = findLoadedClass(name);


//如果没找到 缓存 则进入 if 语句


if (c == null) {


try {


if (parent != null) {


//1、前面我就告诉过大家 parent =》 BootClassLoader


//2、也就是说 先在 BootClassLoader 里找类


c = parent.loadClass(name, false);


} else {


//如果你的 parent==null 系统调用 findBootstrapClassOrNull 方法查找,看方法名字就知


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;


}


源码分析 注释已经写得很清楚了,在这里面就涉及到传说中的 双亲委托机制


为什么要用这种 双亲委托机制 ?


定义:某个类加载器在加载类时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成委托加载任务,就成功返回;只有父类加载器无法完成加载任务或者没有父类加载器时,才自己去加载。


使用原因:


  • 避免重复加载,当父类加载器已经加载了该类的时候,就没必要子 ClassLoader 在加载一次。


举例:加载 MainActivity 时肯定 得加载其父类??Activity,而?Activity 是由 父加载器?BootClassLoader 加载了,那你不用 双亲委托机制 ,非得 PathClassLoader 自己去加载,那不是重复了吗!!!


  • 安全性考虑,防止核心 API 库被随意篡改。


举例:String 类 我们都知道是系统自带的 是由?BootClassLoader 加载,而你不用?双亲委托机制 ,非得用?PathClassLoader 加载,那不是加载到你写的?String 类了,这样很不安全!!!


双亲委托机制 是我们本段内容的一个小插曲,我们回归主题,看一下 PathClassLoader 的?findClass() ,(PathClassLoader 源码很简单,当然没有我们想要的,所以我们得看其直接父类的(BaseDexClassLoader)实现)


public class BaseDexClassLoader extends ClassLoader {


/什么是 DexPathList 呢?解释如下:/


/**


  • A pair of lists of entries, associated with a {@code ClassLoader}.

  • One of the lists is a dex/resource path — typically referred

  • to as a "class path" — list, and the other names directories


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


  • containing native code libraries. Class path entries may be any of:

  • a {@code .jar} or {@code .zip} file containing an optional

  • top-level {@code classes.dex} file as well as arbitrary resources,

  • or a plain {@code .dex} file (with no possibility of associated

  • resources).

  • <p>This class also contains methods to use these lists look up

  • classes and resources.</p>


*/


/*这是关联一个 ClassLoder 的条目列表,这其中有 dex/resource path


通常称为“class path” ,其他名称目录包含本地代码库,class path 条目


可能是包含一个可选的顶级 class.dex 的 zip 文件,jar 文件,以及任意资源


*/


private final DexPathList pathList;


/*重写了 ClassLoder 的这个方法,这个方法会在 loadClass 中调用,当 loadClass 时,具体步骤是这样的:


先查找已经加载的类,如果有返回,如果没有,用父装载器去加载这个类,如果失败,则会调用我们重写的 findclass 这个方法*/


@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;

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
Android热修复基础篇(二),android设计模式面试题