Android ClassLoader类加载器简析

1. Android中有哪几种ClassLoader?他们的作用和区别是什么?

Android中类加载器有5种ClassLoader。BootClassLoader,URLClassLoader,BaseDexClassLoader都最终继承自java.lang.ClassLoader,而DexClassLoader,PathClassLoader,InMemoryDexClassLoader则继承自BaseDexClassLoader。

BootClassLoader

Android中默认无父构造器传入的情况下,默认父构造器为一个PathClassLoader且此PathClassLoader父构造器为BootClassLoader。因此,BootClassLoader是作为最终父类的类构造器。BootClassLoader是ClassLoader中的内部类,是包内可见,我们没法使用,也不能使用动态加载。

URLClassLoader

URLClassLoader继承自SecureClassLoader,SecureClassLoader继承自ClassLoader。URLClassLoader只能用于加载JAR文件,但是由于 dalvik 不能直接识别JAR,所以在Android中无法使用这个加载器。

BaseDexClassLoader

BaseDexClassLoader继承自ClassLoader,用于加载各种dex中的类。 PathClassLoader和DexClassLoader都只是在构造函数上对其简单封装而已.

BaseDexClassLoader的构造函数包含四个参数,分别为:

dexPath,指目标类所在的APK、DEX或JAR文件的路径(可以是SD卡的路径),类装载器将从该路径中寻找指定的目标类。如果要包含多个路径,路径之间必须使用特定的分割符分隔,特定的分割符可以从System.getProperty(“path.separtor”)获得。最终做的是将dexPath路径上的文件ODEX优化到内部位置optimizedDirectory,再进行加载的。

File optimizedDirectory,由于dex文件被包含在APK或者Jar文件中,因此在装载目标类之前需要先从APK或Jar文件中解压出dex文件,该参数就是制定解压出的dex文件存放的路径。这也是对apk中dex根据平台进行ODEX优化的过程。其实APK是一个程序压缩包,里面包含dex文件,ODEX优化就是把包里面的执行程序提取出来,就变成ODEX文件,因为你提取出来了,系统第一次启动的时候就不用去解压程序压缩包的程序,少了一个解压的过程。这样的话系统启动就加快了。为什么说是第一次呢?是因为DEX版本的只有第一次会解压执行程序到 /data/dalvik-cache(针对PathClassLoader)或者optimizedDirectory(针对DexClassLoader)目录,之后也是直接读取目录下的的dex文件,所以第二次启动就和正常的差不多了。当然这只是简单的理解,实际生成的ODEX还有一定的优化作用。ClassLoader只能加载内部存储路径中的dex文件,所以这个路径必须为内部路径。

libraryPath,指目标类中所使用的C/C++库存放的路径。

ClassLoader parent,是指该装载器的父装载器,一般为当前执行类的装载器,例如在Android中以context.getClassLoader()作为父装载器。

PathClassLoader


可以看出PathClassLoader将optimizedDirectory置为Null,也就是没设置优化后的存放路径。其实optimizedDirectory为null时的默认路径就是/data/dalvik-cache 目录。因此,PathClassLoader是用来加载Android系统类和app应用的类的。

DexClassLoader


DexClassLoader支持加载包含classes.dex的JAR/APK文件,可以是SD卡上的路径。
上面说dalvik不能直接识别JAR,DexClassLoader却可以加载JAR文件,这难道不矛盾吗?其实在BaseDexClassLoader里对”.jar”,”.zip”,”.apk”,”.dex”后缀的文件最后都会生成一个对应的dex文件,所以最终处理的还是dex文件,而URLClassLoader并没有做类似的处理。一般我们都是用这个DexClassLoader来作为动态加载的加载器。

InMemoryDexClassLoader


InMemoryDexClassLoader是在API26时新增的类加载器,继承自BaseDexClassLoader。
InMemoryDexClassLoader的构造函数调用其父类DexClassLoader的构造函数,ByteBuffer数组构造了一个DexPathList,可用于内存中的DEX文件。

DelegateLastClassLoader

DelegateLastClassLoader是在API27时新增的类加载器,继承自PathClassLoader。DelegateLastClassLoader实行最后查找策略。使用DelegateLastClassLoader来加载的每个类或资源,使用以下查找顺序:
首先,判断是否已经加载过该类。
然后,搜索此类的类加载器是否加载过这个类。
最后,搜索与此类加载器的dexPath关联的dex文件列表,委托给指定的父对象加载。

2. 简述ClassLoader的双亲委托模型

双亲委托模型是指先委托父加载器寻找目标类,只有在找不到的情况下才从自己的类路径中查找并加载目标类。这样一方面可以避免重复加载,另一方面可以避免有人恶意编写一个类(如java.lang.String)并加载到JVM中,java.lang.String永远都是由根加载器来加载。

3. 简述双亲委托模型在热修复领域的应用

一个ClassLoader可以有多个DEX文件,每个Dex文件是一个Element,多个Dex文件排成一个有序数组dexElements,当找类的时候,会按照顺序遍历DEX文件,然后从当前遍历的DEX文件中找类,由于双亲委托模型机制,只要找到就会停止查找并返回,如果找不到就从下一个DEX文件继续查找。只要我们先加载修复好的DEX文件,那么就不会加载有bug的DEX文件了。
另外,假设app中有个类叫做A,再其内部引用了B。发布过程中发现B有编写错误,那么想要发布一个新的B类,那么你就要阻止A这个类打上CLASS_ISPREVERIFIED的标志。

参考资料:Android动态加载之ClassLoader详解

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值