类加载

Catalogue   

类加载过程

加载,验证,准备,解析,初始化,使用,卸载

加载

  • 使用 new 关键字实例化对象,读取或者设置一个类的静态变量(被 final修饰的除外,已经在编译器被加入常量池),以及调用一个类的静态方法的 时候
  • 对类进行反射调用的时候
  • 当初始化一个类时,如果其父类没有被加载,则先对其父类进行加载
  • 当虚拟机启动的时候,用户指定的(包含 main 方法)的类会被加载

在类的加载阶段,虚拟机会完成以下三件事情:

  • 通过一个类的全限定名获取定义类的二进制字节流
  • 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
  • 在 Java 堆中生成一个代表这个类的 Class 对象,作为方法区这些数据的访问入口。

验证

这一阶段是为了确保 class 文件的字节流包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。主要包括以下几个过程:

  • 文件格式验证
  • 元数据验证
  • 字节码验证
  • 符号引用验证

准备

准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些内存都将在 方法区中进行分配。这个阶段中进行内存分配的变量只有被 static 修饰的变量,
并将其设置为默认值,而真正的赋值则在初始化阶段。另外,被 final static 字段 修饰的常量在编译器就已经被赋值。

解析

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

初始化

初始化阶段是执行类构造器<cinit>()方法的过程。

<cinit>()与类的构造方法不同,<cinit>()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块中的语句合并而成的。
编译器收集的顺序是按语句在源文件中出现的顺序决定的,静态语句块中只能访问定义在它之前的静态变 量,定义在它之后的静态变量,只可以赋值,不可以访问。

虚拟机会保证子类的<cinit>()方法执行之前,其父类的<cinit>()方法一定被执行 (父类先与子类完成加载过程)