Java 类加载的过程 加载、验证、准备、解析、初始化
发布日期:2021-05-08 12:14:48 浏览次数:9 分类:精选文章

本文共 1926 字,大约阅读时间需要 6 分钟。

7.3 类加载的过程

接下来我们将深入了解Java虚拟机中类加载的全过程,即加载、验证、准备、解析和初始化这五个阶段所执行的具体动作。


7.3.1 加载

“加载”(Loading)阶段是整个“类加载”(Class Loading)过程中的一个阶段。在加载阶段,Java虚拟机需要完成以下三件事情:

  • 通过一个类的全限定名来获取定义此类的二进制字节流

    这一规则并没有指明二进制字节流必须得从某个Class文件中获取,确切地说是根本没有指明要从哪里获取、如何获取。
    这一开放性使得Java发展历程中,许多创新的技术都建立在此基础之上,例如从ZIP压缩包中读取、从网络中获取、运行时计算生成等。

  • 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构

  • 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口


  • 7.3.2 验证

    验证是连接阶段的第一步,其目的是确保Class文件的字节流中包含的信息符合《Java虚拟机规范》的全部约束要求,保证这些信息被当作代码运行后不会危害虚拟机自身的安全。

    验证阶段的主要内容包括:

  • 文件格式验证

    • 检查Class文件是否以魔数0xCAFEBABE开头。
    • 检查主版本号和次版本号是否在当前Java虚拟机接受范围之内。
    • 检查常量池中的常量是否包含不被支持的常量类型。
    • 检查指向常量的各种索引值是否存在指向不存在的常量或不符合类型的常量。
    • 检查CONSTANT_Utf8_info型的常量是否包含不符合UTF-8编码的数据。
    • 检查Class文件中各个部分及文件本身是否有被删除的或附加的其他信息。
  • 元数据验证

    • 检查类是否有父类(除了java.lang.Object之外,所有的类都应当有父类)。
    • 检查类的父类是否继承了不允许被继承的类(被final修饰的类)。
    • 检查类中的字段、方法是否与父类产生矛盾(例如覆盖了父类的final字段,或者出现不符合规则的方法重载)。
  • 字节码验证

    • 通过数据流分析和控制流分析,确定程序语义是合法的、符合逻辑的。
    • 确保操作数栈的数据类型与指令代码序列配合工作。
    • 确保跳转指令不会跳转到方法体以外的字节码指令上。
    • 确保类型转换总是有效的。
  • 符号引用验证

    • 确保符号引用中的类、字段、方法的可访问性(private、protected、public、
      )是否可被当前类访问。
    • 确保符号引用中的类、字段、方法是否存在缺失或被禁止访问的情况。

  • 7.3.3 准备

    准备阶段是正式为类中定义的变量(即静态变量,被static修饰的变量)分配内存并设置类变量初始值的阶段。

    • 内存分配

      • 类变量将被分配到方法区中。
      • 实例变量将随着对象实例化而分配到Java堆中。
    • 初始值

      • 类变量的初始值通常是数据类型的零值。
      • 如果类字段的字段属性表中存在ConstantValue属性,那么变量值会被初始化为ConstantValue属性所指定的初始值。

    7.3.4 解析

    解析阶段是Java虚拟机将常量池内的符号引用替换为直接引用的过程。

    解析的主要目标包括:

  • 类或接口的解析

    • 如果要解析一个未被解析过的符号引用N,虚拟机将通过类加载器加载目标类C。
    • 如果C是一个数组类型,虚拟机将加载数组元素类型,并生成相应的数组对象。
    • 需要进行符号引用验证,确认解析类C是否具备对解析类D的访问权限。
  • 字段解析

    • 需要解析字段表中的class_index项,找到字段所属的类或接口。
    • 在目标类中查找是否存在匹配字段,递归查找父类和接口。
    • 如果查找成功,将返回字段的直接引用,并进行权限验证。
  • 方法解析

    • 需要解析方法表中的class_index项,找到方法所属的类或接口。
    • 在目标类中查找是否存在匹配方法,递归查找父类和实现的接口。
    • 如果查找成功,将返回方法的直接引用,并进行权限验证。
  • 接口方法解析

    • 需要解析接口方法表中的class_index项,找到方法所属的接口或类。
    • 在目标接口中查找是否存在匹配方法,递归查找父接口。
    • 如果查找成功,将返回方法的直接引用,并进行权限验证。

  • 7.3.5 初始化

    类的初始化阶段是类加载过程的最后一个步骤。

    • 方法的执行

      • 方法是由编译器自动生成的类构造器方法,负责初始化类变量和静态语句块。
      • 方法会在类加载完成后被执行。
    • 静态语句块的执行

      • 静态语句块中的语句只能访问到定义在静态语句块之前的变量。
      • 父类的
        方法会在子类的
        方法执行前被执行。
    • 线程安全

      • Java虚拟机会对
        方法进行加锁同步,确保多线程环境下类的初始化是安全的。

    参考文献

  • 《深入理解Java虚拟机:JVM高级特性与最佳实践》(第3版)- 周志明
  • Java官方文档
  • 上一篇:Java中的 异常、异常类、异常处理、如何使用异常
    下一篇:Java Web ---Tomcat的基本理解

    发表评论

    最新留言

    能坚持,总会有不一样的收获!
    [***.219.124.196]2025年04月01日 08时34分49秒