汇总:Android小白成长之路_知识体系汇总【持续更新中…】
目录
ClassLoader是什么
ClassLoader
就是类加载器,虚拟机是无法直接加载class字节码文件的,需要通过ClassLoader
将字节码文件经过一系列的处理,最终形成虚拟机可以直接读取的Class
对象
类加载流程
类加载流程可以简单地总结为:
- 加载:通过不同的
ClassLoader
把各个来源的Class
字节码文件加载到内存中 - 验证:验证加载进来的字节流是否符合虚拟机的规范,预防通过特殊处理生成的不规范字节流被加载进内存
- 文件格式验证:验证字节流是否符合
Class
文件格式的规范,并能被当前版本的虚拟机处理, - 元数据验证和字节码验证:对字节码的语义分析和对数据流进行分析,确保代码逻辑正确
- 符号引用验证:通过字符串形式描述的类是否存在,类的定义是否符合规范
- 文件格式验证:验证字节流是否符合
- 准备:为类变量(被
static
修饰的变量)分配内存和赋初值,这里的默认初始值不是我们代码里写的初值,而是java虚拟机根据类型赋的初值,例如int初值为0 - 解析:将常量池的符号引用替换成直接引用,虚拟机把所有的类名、方法名、字段名等符号引用替换为具体的内存地址或偏移量
- 初始化:对类变量进行初始化,主要执行静态变量的初始化,包括静态变量的赋值和静态初始化块的执行
双亲委托机制
- 对于两个类,当且仅当两个类都来源于同一个Class文件,并且被同一个类加载器加载,虚拟机才认为它们是同一个类
- 双亲委托机制:
- 当前
ClassLoader
首先从自己的加载缓存中查询是否此类已加载过,如果已加载则直接返回此类 - 如果在当前
ClassLoader
没加载过,则委托父类加载器去加载,父类加载器也采用同样的策略,先查看自己的缓存,没有则继续委托父类加载去加载,一直到最高层类加载器 - 当所有父类加载器都没有加载的时候,再由当前的类加载器进行加载,并且把它放入自己的缓存中
- 当前
- 父类加载器并不是指当前
ClassLoader
的父类,而是指当前ClassLoader
的parent
字段所对应的类, - 双亲委托机制的作用:
- 防止重复加载同一个Class:加载过的Class会被直接返回
- 保证核心库的Class不被篡改:核心库的Class由高层父类加载器加载,即使我们自己更改了某个核心库的类并且使用类加载器加载,也会交由父类加载器加载,而父类加载器已经加载过此类,就会直接返回已加载过的,避免核心库被篡改
- 破坏双亲委托机制方法:自定义ClassLoader,并重写
loadClass
方法,不按照双亲委托机制,实现自己的逻辑
Java中的ClassLoader
-
BootstrapClassLoader
:最顶层的加载类,主要加载核心类库,通常为JDK目录下的jre/lib
里的类库进行加载 -
ExtensionClassLoader
:它的父类加载器为BootstrapClassLoader
,它主要对JDK目录下的jre/lib/ext
目录里的类库进行加载,JAVA 9
及其之后替换为PlatformClassLoader
-
AppClassLoader
:应用程序类加载器,它的父类加载器为ExtensionClassLoader
,负责加载应用程序CLASSPATH
目录下的所有jar
和Class
文件
Android中的ClassLoader
- 由于Android中加载的不再是Class文件,而是
Dex
文件,因此Android中没有ExtensionClassLoader和AppClassLoader -
BootClassLoader
:在系统启动时创建,在App启动时将其传进来,用于加载一些系统Framework
层级需要的类 -
DexClassLoader
和PathClassLoader
:可以从目录中加载APK、DEX和JAR,这两者的差别是PathClassLoader没有将optimizedDirectory
置为Null
,也就是没设置优化后的存放路径。其实optimizedDirectory为null时的默认路径就是/data/dalvik-cache
目录。PathClassLoader是用来加载Android系统类和应用的类。而DexClassLoader可以指定optimizedDirectory,但到了Android 8.0之
后,这个字段被弃用了,也就是说DexClassLoader指定了optimizedDirectory也不起作用了
类加载应用场景
- 热加载
- 加密保护