深入理解Java类加载

类文件和字节码

简单来说,类加载就是将一个新类型加载到运行时的 JVM 的过程,加载后的类型才能被 Java 进程使用


这里我们重点讨论的是 Class 对象它代表 JVM 中的类型,而这些概念可以构成 Java 中的主要特性(如反射)

然后我们将探讨字节码,来研究各种类型的运行时的工作原理

类型对象

在.class 文件中,定义了类型,包括字段\方法\继承信息\注解\其他元数据.

类是 java 平台解析\验证\执行程序代码的基本单元

开发人员只需要提供可以运行的 jar 文件或应用程序的类名(必须在类路径中),JVM 就会找到并运行该类
如果想要引入第三方依赖,那么也必须在类路径中

一个简单的例子,

Class<?> clazz = Class.forName("MyClass")

它将 MyClass 这个类加载到当前运行时,而在底层其实完成了很多工作

  1. 首先找到这个名为 MyClass 的类文件
  2. 然后解析其中包含的类

从较高层次来看,这个过程其实就是在构建 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 才开始执行新加载类的字节码
完成初始化后,此时这个类就可以被用于运行时环境了,如果有其他链接阶段的类引用该类,就会看到这个类已经完全加载并且可用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值