ljzsdut
GitHubToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeBack to homepage

01 类加载器

Java虚拟机与程序的生命周期

在Java代码中,类型的加载、连接与初始化过程都是在程序运行期间完成的。

类加载、连接、初始化

class Test {
  public static int a = 1;
}

加载:(从磁盘)查找并加载类的二进制数据(到内存中) 连接:

  • 验证: 确保被加载的类的正确性
  • 准备:为类的静态变量分配内存,并将其初始化为默认值
  • 解析:把类中的符号引用转换为直接引用

初始化:为类的静态变量赋予正确的初始值

类使用、卸载

使用:程序使用类,比如创建对象、调用方法等

卸载:将内存中的字节码销毁掉。此后无法再使用类。

JVM生命周期的结束

在如下几种情况下,Java虚拟机将结束生命周期 1、执行了System.exit()方法

2、程序正常执行结束

3、程序在执行过程中遇到了异常或错误而异常终止

4、由于操作系统出现错误而导致Java虚拟机进程终止

类的使用

Java程序对类的使用方式可分为两种

  • 主动使用

  • 被动使用

所有的Java虚拟机实现必须在每个类或接口被Java程序“ 首次主动使用 ”时才初始化他们。

主动使用的7种情况

  • 创建类的实例

image-20200303132724973

image-20200303132724973

image-20200303134542076

  • 访问某个类或接口的静态变量(static),或对该静态变量赋值(对于静态字段来说,只有直接定义了该字段的类才会被初始化)

image-20200303131301423

image-20200302180544254

image-20200303132458444

  • 调用类的静态方法

image-20200303141214282

  • 反射(如Class.forName("com.test.Test")

  • 初始化一个类的子类时,会主动使用父类。(当一个类在初始化时,要求其父类全部都已经初始化完毕)接口没有要求父类必须完成初始化。

    image-20200303135955376

  • 包含main方法的类(java虚拟机启动时被表明为启动类的类)

  • 从jdk1.7开始,提供的动态语言支持。如果调用时对应的类没有初始化,则会初始化。

被动使用

除了以上7种,其它使用java类的方法都呗看做对类的被动使用,都不会导致类的初始化

image-20200303142315338

类的加载

类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在内存中创建一个java.lang.Class对象(规范并未说明 Class对象位于哪里, HotSpot虚拟机将其放在了方法区中)用来封装类在方法区内的数据结构。

类的加载的最终产品是位于内存中的Class对象。 Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口。

有两种类型的类加载器:

  • Java虚拟机自带的加载器
    • 根类加载器(Bootstrap)
    • 扩展类加载器(Extension)
    • 系统(应用)类加载器(System)
  • 用户自定义的类加载器
    • java.lang.ClassLoader的子类
    • 用户可以定制类的加载方式

类加载器并不需要等到某个类被“首次主动使用”时再加载它。

  • JVM规范允许类加载器在预料某个类将要被使用时就预先加载它,如果在预先加载的过程中遇到了.class文件缺失或存在错误,类加载器必须在程序首次主动使用该类时才报告错误(LinkageError 错误)
  • 如果这个类直没有被程序主动使用,那么类加载器就不会报告错误。

类加载器

父亲也会委托其父亲的。

image-20200303145242144

image-20200303145450039

image-20200303153248507

类的连接

类被加载后,就进入连接阶段。连接就是将已经读入到内存的类的二进制数据合并到虚拟机的运行时环境中去。

类的验证

类的验证的内容:

  • 类文件的结构检查
  • 语义检查
  • 字节码验证
  • 二进制兼容性的验证

类的准备

image-20200303144129990

类的初始化

image-20200303144157303

image-20200303144418752

类的初始化步骤:

  • 假如这个类还没有被加载和连接,那就先进行加载和连接
  • 假如类存在直接父类,并且这个父类还没有被初始化,那就先初始化直接父类
  • 假如类中存在初始化语句,那就依次执行这些初始化语句

image-20200303144854326

image-20200303152026287

调用ClassL oader类的loadClass方法加载一个类,并不是对类的主动使用,不会导致类的初始化。