Java虚拟机是如何加载Java类的?

Java 虚拟机将字节流转化为 Java 类,按先后顺序需要经过加载、链接以及初始化三大步骤。

加载

加载,是指查找字节流,并且据此创建类的过程。加载需要借助类加载器。

双亲委派模型:每当一个类加载器接收到加载请求时,它会先将请求转发给父类加载器。在父类加载器没有找到所请求的类的情况下,该类加载器才会尝试去加载。

在 Java 9 之前,启动类加载器负责加载最为基础、最为重要的类,比如存放在 JRE 的 lib 目录下 jar 包中的类(以及由虚拟机参数 -Xbootclasspath 指定的类)。除了启动类加载器之外,另外两个重要的类加载器是扩展类加载器(extension class loader)和应用类加载器(application class loader),均由 Java 核心类库提供。

扩展类加载器的父类加载器是启动类加载器。它负责加载相对次要、但又通用的类。

应用类加载器的父类加载器则是扩展类加载器。它负责加载应用程序路径下的类。默认情况下,应用程序中包含的类便是由应用类加载器加载的。

除了加载功能之外,类加载器还提供了命名空间的作用。

在 Java 虚拟机中,类的唯一性是由类加载器实例以及类的全名一同确定的。即便是同一串字节流,经由不同的类加载器加载,也会得到两个不同的类。

链接

链接,是指将创建成的类合并至 Java 虚拟机中,使之能够执行的过程。它可分为验证准备以及解析三个阶段。

  • 验证 阶段的目的,在于确保被加载类能够满足 Java 虚拟机的约束条件。

  • 准备 阶段的目的,则是为被加载类的静态字段分配内存。

  • 解析 阶段的目的,是将这些符号引用解析成为实际引用。如果符号引用指向一个未被加载的类,或者未被加载类的字段或方法,那么解析将触发这个类的加载。

初始化

初始化,便是为标记为常量值的字段赋值。在 Java 代码中,如果要初始化一个静态字段,我们可以在声明时直接赋值,也可以在静态代码块中对其赋值。

  • 类的初始化何时会被触发呢?JVM 规范枚举了下述多种触发情况:
  1. 当虚拟机启动时,初始化用户指定的主类;
  2. 当遇到用以新建目标类实例的 new 指令时,初始化 new 指令的目标类;
  3. 当遇到调用静态方法的指令时,初始化该静态方法所在的类;
  4. 当遇到访问静态字段的指令时,初始化该静态字段所在的类;
  5. 子类的初始化会触发父类的初始化;
  6. 如果一个接口定义了 default 方法,那么直接实现或者间接实现该接口的类的初始化,会触发该接口的初始化;
  7. 使用反射 API 对某个类进行反射调用时,初始化这个类;
  8. 当初次调用 MethodHandle 实例时,初始化该 MethodHandle 指向的方法所在的类。

你可能感兴趣的:(java,开发语言,后端)