Dalvik/ART 虚拟机加载类和资源也是用ClassLoader,不过JVM通过ClassLoader加载的class字节码,而Dalvik/ART VM通过ClassLoader加载则是dex。
一、类装载流程
JVM将整个类加载过程划分为了三个步骤:
1、装载
装载过程负责找到二进制字节码(.class)并加载至JVM中,JVM通过类名、类所在的包名、ClassLoader来完成类的加载,同样,也采用以上三个元素来标识一个被加载了的类:类名 + 包名 + ClassLoader实例ID。启动类加载器 (BootStrap class Loader)、扩展类加载器(Extension class Loader)和应用程序类加载器(Application class Loader) 这三种类加载器帮助完成类的加载。
2、链接
链接过程负责对二进制字节码的格式进行校验、初始化装载类中的静态变量以及解析类中调用的接口、类。在完成了校验后,JVM初始化类中的静态变量,并将其值赋为默认值。最后一步为对类中的所有属性、方法进行验证,以确保其需要调用的属性、方法存在,以及具备应的权限(例如public、private域权限等),会造成NoSuchMethodError、NoSuchFieldError等错误信息。
- 校验 – 字节码校验器会校验生成的字节码是否正确,如果校验失败,我们会得到校验错误。
- 准备 – 分配内存并初始化默认值给所有的静态变量。
- 解析 – 所有符号内存引用被方法区(Method Area)的原始引用所替代。
3、初始化
初始化过程即为执行类中的静态初始化代码、构造器代码以及静态属性的初始化,在四种情况下会触发执行初始化过程。
- 调用了new关键字
- 类字面常量
- 反射调用了类中的方法
- 子类调用了初始化
- JVM启动过程中指定的初始化类
二、loadClass() 是类加载的入口,双亲委托模式
双亲委派模型要求除了顶层的启动类加载器外,其余的类加载器都应当有自己的父类加载器。
双亲委派模型的工作过程是:
- 如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成。
- 每一个层次的类加载器都是如此。因此,所有的加载请求最终都应该传送到顶层的启动类加载器中。
- 只有当父加载器反馈自己无法完成这个加载请求时(搜索范围中没有找到所需的类),子加载器才会尝试自己去加载。
系统提供的类加载器
- 启动类加载器(Bootstrap ClassLoader):<JAVA_HOME>\lib
- 扩展类加载器(Extension ClassLoader):<JAVA_HOME>\lib\ext
- 应用程序类加载器(Application ClassLoader):加载用户类路径上所指定的类库
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name); //是否已经加载过
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false); //没有加载过且父类不为null,委托父类进行加载
} else {
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;
}
双亲委托模式:委托是从下向上,然后具体查找过程却是自上至下。
对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在虚拟机中的唯一性
双亲委托模式的优点
- 安全性
- 避免重复加载
参考
浅谈双亲委派模型