内容提要
文章介绍Java类加载机制,参考《深入理解Java虚拟机》。类生命周期分七阶段:加载、验证、准备、解析、初始化、使用、卸载。加载获取二进制字节流并生成Class对象;验证检查格式等;准备为静态变量分配内存;解析将符号引用替换为直接引用;初始化执行类构造器,合并静态变量赋值和静态块,保证父类先于子类。
延伸解读
类加载的七个阶段与链接阶段
类生命周期分为加载、验证、准备、解析、初始化、使用、卸载七个阶段,其中验证、准备、解析合称链接阶段。链接阶段将加载得到的二进制字节流数据合并到JVM运行时状态中,为后续初始化做准备。理解这一划分有助于定位类加载过程中的问题,例如验证失败或解析错误通常发生在链接阶段。
初始化阶段与<clinit>方法
初始化阶段执行类构造器<clinit>方法,该方法由Javac编译器自动生成,收集静态变量赋值和静态块语句,顺序与源码出现顺序一致。静态块只能访问其之前定义的变量,之后定义的变量只能赋值不能访问。此外,父类的<clinit>先于子类执行,且需保证多线程下的并发安全。
类加载与双亲委派模型的关系
文章虽提及双亲委派模型,但主要内容是类加载机制的基础阶段。双亲委派模型是类加载器协作的规则,而生命周期描述的是类从加载到卸载的完整过程。理解两者区别有助于深入掌握JVM类加载机制,避免混淆概念。
Q&A
Java类加载机制中,一个类的生命周期包括哪些阶段?
一个类的生命周期包括七个阶段:加载、验证、准备、解析、初始化、使用和卸载。其中验证、准备、解析三个阶段合称为链接阶段。
Java类加载的加载阶段具体做了什么?
加载阶段通过类的全限定名获取定义此类的二进制字节流,将字节流代表的静态存储结构转化为方法区的运行时数据结构,并在内存中生成一个代表该类的java.lang.Class对象,作为方法区中该类各种数据的访问入口。
Java类加载的验证阶段包括哪些子步骤?
验证阶段包括文件格式验证、元数据验证、字节码验证和符号引用验证。
准备阶段和初始化阶段有什么区别?
准备阶段是为类中定义的静态变量分配内存并设置类变量初始值(通常为零值),而初始化阶段是执行类构造器<clinit>()方法的过程,该方法由编译器自动收集类变量的赋值动作和静态代码块合并产生,并保证父类的初始化先于子类。
解析阶段在类加载过程中起什么作用?
解析阶段是将Java虚拟机常量池内的符号引用替换为直接引用的过程,是链接阶段的一部分。
类构造器<clinit>()方法是如何生成的?
<clinit>()方法不是Java代码中直接编写的方法,而是Javac编译器的自动生成物。它由编译器自动收集类中的所有类变量的赋值动作和静态代码块(static{}块)中的语句合并产生,收集顺序由语句在原文件中出现的顺序决定。
在静态代码块中访问后面定义的变量有什么限制?
静态语句块中只能访问定义在它之前的变量;对于定义在它之后的变量,前面的静态语句块可以赋值,但不能访问。
类加载过程中,方法区会存储哪些类信息?
方法区会存储当前类的类信息,包括类的静态变量、类初始化代码(定义静态变量时的赋值语句和静态初始化代码块)、实例变量定义、实例初始化代码(定义实例变量时的赋值语句、实例代码块和构造方法)和实例方法,以及父类的类信息引用。