类加载过程
悲观者从机会中看到困难。乐观者从困难中看到机会。
——温斯顿·丘吉尔

1.加载
类的加载是指将读取类的class文件,将其转化为某种静态数据结构存储在方法区内,并在堆中为之创建一个Class类对象。类的加载过程是由类加载器完成,类加载器由JVM提供。我们也自己也可以通过继承ClassLoader来实现自己的类加载器
- 根加载器Boot Strap ClassLoader
- 扩展类加载器 Extension ClassLoader
- 应用加载器 Application ClassLoader
- 用户自定义类加载器:---UserClassLoader
这些类加载器之间的关系形成了双亲委派模型,其核心思想是当一个类加载器收到类加载的请求时,首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一层次的类加载器都是如此因此所有的加载请求最终都应该传送到顶层的启动类加载器中。
只有当父加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。
2.链接
虽然通过类的加载,堆中已经创建了一个Class对象。链接负责将二进制数据合并到JRE中。链接需要通过验证、准备、解析三个阶段
-
验证:虽然通过类的加载,堆中已经创建了一个Class对象。并不代表JVM已经认可了这个类,如果程序想要使用这个类,就必须经过链接,而链接的第一部分就是验证,(1.对类的元数据的验证 2.字节码的验证,简单概括就是对class静态结构进行语法和语义上的分析,保证其不会危害虚拟机行为)如果通过了加载和验证,暂且认为该class是安全的。但是并不意味着验证已经完全结束,还有就是对符号引用进行验证,这个阶段是发生在解析阶段内的
-
准备:经过验证后,会进入准备阶段,就是为该类型中的静态变量赋默认值
-
解析:可以在初始化之前或之后进行的。这个阶段就是为符号引用解析为直接引用。
Java在编译阶段,假如A引用了B,在A进行编译的时候,A是不知道B有没有被编译,而且B一定也没有被加载,所有A一定不知道B的实际地址,A怎么才能找到B呢,此时在A的class文件中使用一个字符串S来代表B的地址,S就被称为符号引用,在运行时呢,如果A发生了类加载,在解析阶段B还未被加载,那么就会触发B的加载,将B加载到虚拟机中,此时A中B的符号引用会被替换为B的实际地址如果B是一个具体的实现类,那么就被称为静态解析
如果B是一个抽象类或者接口,那么他可能由几个具体的实现类C/D,此时B的具体实现并不明确,当然也不知道使用哪个具体类的引用来替换符号引用,既然不知道就等一等,直到运行时发生了调用,此时虚拟机调用栈将会得到具体的类型信息,这时候再进行解析,就会有明确的直接引用来替换符号引用。这也是为什么有时候解析阶段会发生在初始化阶段之后,这就是动态解析,用他来实现了多态
3.初始化
当解析步骤完成,意味着整个链接部分的完成,这也就是外部加载的Java类已经成功的引入到了你的程序中。初始化就是此时会判断代码中是否存在主动的资源初始化操作
4.使用
使用类或者创建对象
5.卸载
如果有下面的情况,类就会被卸载:
- 该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例。
- 加载该类的ClassLoader已经被回收。
- 类对应的Java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法

浙公网安备 33010602011771号