类文件和字节码
简单来说,类加载就是将一个新类型加载到运行时的 JVM 的过程,加载后的类型才能被 Java 进程使用
这里我们重点讨论的是 Class 对象它代表 JVM 中的类型,而这些概念可以构成 Java 中的主要特性(如反射)
然后我们将探讨字节码,来研究各种类型的运行时的工作原理
类型对象
在.class 文件中,定义了类型,包括字段\方法\继承信息\注解\其他元数据.
类是 java 平台解析\验证\执行程序代码的基本单元
开发人员只需要提供可以运行的 jar 文件或应用程序的类名(必须在类路径中),JVM 就会找到并运行该类
如果想要引入第三方依赖,那么也必须在类路径中
一个简单的例子,
Class<?> clazz = Class.forName("MyClass")
它将 MyClass 这个类加载到当前运行时,而在底层其实完成了很多工作
- 首先找到这个名为 MyClass 的类文件
- 然后解析其中包含的类
从较高层次来看,这个过程其实就是在构建 JVM 的 klass. 如果可以从类文件中成功提取 klass(这是 JVM 的内部对象).JVM 就会构造这个 klass 的镜像,并将这个作为 Class 对象传递给 Java 代码.然后,我们就可以使用该类型了,并构建它的新实例,所有类加载都遵循这个过程,其中也包括依赖
clazz 被赋予的是 MyClass 类型,而不是 klass,因为 klass 是 JVM 的内部表示
Class对象也是常规的Java对象,它们被存储在Java堆中,与其他类型一样
加载和链接
JVM 会按照字节数据流的格式来读取类文件的内容,然后将其添加到运行时.这个过程可以分为加载和链接
加载
JVM 从文件中读取内容并存储到字节数组中(当然也可以是其他形式)
一旦读取了数据流,就需要对它解析,检查是否满足有效的类文件结构(这个过程也叫做格式检查)
如果格式检查正确: JVM 会创建一个 klass,然后填充它的信息.并执行一些基本检查,比如访问控制
链接
类加载过程结束后,此时类还不能被其他代码使用,因为此时它还不是一个功能完备的类.我们需要对类进行链接,然后在使用前对其初始化.
这个链接过程分为 3 个子阶段: 验证\准备\解析
验证
这个阶段进行的主要检查
- 确保字节码不会尝试非法操作栈
- 确保每条分支(如 if 或循环)都有正确的目标指令
- 确保调用方法时参数的数量和类型正确
- 确保局部变量赋值的类型正确
- 确保每个可能抛出的异常都有做合法捕获处理
这种检查只在验证阶段,运行时会跳过这些检查,不必担心速度问题.
还有一些检查可以简化字节码到机器码的编译过程,也就是我们所说的即时编译
准备
涉及到内存分配\还有为静态变量初始化做准备(但它不会初始化变量,也不会执行任何 JVM 字节码)
解析
JVM 会检查被链接类的父类(以及接口)是否已经被链接.如果没有,JVM 会先链接父类,在链接间接父类.这可能会递归链接以前没见过的新类型
所谓的传递闭包,就是不仅类之间继承的类型需要链接,所有间接引用的类型也必须链接
初始化
一旦找到和解析了所有需要加载的附加类型,就可以执行初始化操作了
初始化这是类加载的最后阶段.在此阶段,静态变量会被初始化,静态初始化块也会被初始化.知道此时,JVM 才开始执行新加载类的字节码
完成初始化后,此时这个类就可以被用于运行时环境了,如果有其他链接阶段的类引用该类,就会看到这个类已经完全加载并且可用
1002

被折叠的 条评论
为什么被折叠?



