Java 类的生命周期指的是一个类从加载到内存到卸载出内存的整个过程。这一过程主要包括以下几个阶段:
- 加载(Loading)
- 连接(Linking)
- 验证(Verification)
- 准备(Preparation)
- 解析(Resolution)
- 初始化(Initialization)
- 使用(Usage)
- 卸载(Unloading)
1. 加载(Loading)
类加载器(Class Loader)将字节码文件(.class 文件)读取到内存中,生成一个 java.lang.Class
对象。类加载器分为以下几种:
- Bootstrap ClassLoader:引导类加载器,加载 JDK 核心类库(
rt.jar
)。- Extension ClassLoader:扩展类加载器,加载 JDK 扩展类库(
lib/ext
目录)。- Application ClassLoader:应用类加载器,加载应用程序的类路径(classpath)上的类。
双亲委派机制
双亲委派机制指的是:当一个类加载器接收到加载类的任务时,会自底向上查找是否加载过,
再由顶向下进行加载。
打破双亲委派机制
打破双亲委派机制历史上有三种方式,但本质上只有第一种算是真正的打破了双亲委派机制:
自定义类加载器并且重写loadClass方法。Tomcat通过这种方式实现应用之间类隔离。为每一个应用创建一个类加载器。
在同一个Java虚拟机中,只有相同类加载器+相同的类限定名才会被认为是同一个类。
2. 连接(Linking)
连接阶段包括验证、准备和解析三个子阶段。
验证(Verification)
确保类的字节码符合 JVM 的规范,不会危害 JVM 的安全。验证过程包括:
- 文件格式验证:检查字节码文件格式是否符合规范。
- 元数据验证:检查类的元数据(如类、字段、方法的描述)是否符合规范。
- 字节码验证:分析数据流和控制流,确保字节码指令不会危害 JVM 的安全。
- 符号引用验证:确保类、字段、方法的符号引用是合法的。
准备(Preparation)
为类的静态变量分配内存,并将其初始化为默认值。注意,这里只是分配内存并初始化默认值,不会执行任何用户定义的初始化代码。
解析(Resolution)
将常量池中的符号引用(如类名、方法名、字段名)替换为直接引用(指向实际内存地址的指针)。
3. 初始化(Initialization)
初始化阶段执行类的初始化代码,包括:
- 静态变量的初始化:按顺序执行静态变量的初始化表达式。
- 静态代码块的执行:按顺序执行静态代码块。
初始化过程是线程安全的,JVM 保证同一个类的初始化代码只会被执行一次。
4. 使用(Usage)
在初始化完成后,类进入使用阶段。在使用阶段,可以创建类的实例、访问静态变量、调用静态方法等。
5. 卸载(Unloading)
当某个类不再被使用,并且对应的 ClassLoader
被垃圾收集器回收时,该类会被卸载出内存。类的卸载是由 JVM 自动进行的,开发者不能显式地卸载类。