首先要明白的是,在Java代码中,类型(class、interface、枚举等,不是对象)的加载、连接与初始化过程都是在程序运行期间完成的。
Java虚拟机与程序的生命周期
在如下的几种情况下,Java虚拟机将会结束生命周期
- 执行了System.exit()方法
- 程序执行结束
- 程序在执行过程中遇到了异常或错误而异常终止
- 由于操作系统出现错误而导致Java虚拟机进程终止
类的加载连接与初始化过程详解
如上图所示,类的加载主要分为三个阶段,分别是:
- 加载:指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区中,然后在内存中创建一个java.lang.Class对象(JVM规范并未说明Class对象位于哪里,HotSpot虚拟机将其放在了方法区中)用来封装类在方法区内的数据结构
- 连接:连接简要来说就是将类与类之间的关系确定好,它又被分为三个过程,依次是:
- 验证:确保被加载类的正确性
- 准备:为类的静态变量分配内存,并将其初始化为默认值(并不用定义时赋的初值)eg:int类型变量默认值为0;
- 把类的符号引用转换为直接引用
- 初始化:为类的静态变量赋予正确的初始值。例如:public static int a=1; 那么初始化类时会将1赋给变量a,1就是a的初始值
除了以上三个阶段,类的加载其实还有使用和卸载两个阶段,这两个阶段在实际开发中接触不多,这里不再介绍。
Java程序对类的使用方式
Java程序对类的使用方式分为两种,一种是主动使用,一种是被动使用。而主动使用的方式又分为以下七种:
- 创建类的实例(即通过new关键字创建的实例)
- 访问某个类或接口的静态变量或者对该静态变量赋值
- 调用类的静态方法
- 反射(如Class.forName(“com.test.Test”))
- 初始化一个类的子类
- Java虚拟机启动时被标明为启动类的类(即拥有main方法)
- JDK 1.7开始提供的静态语言支持:java.lang.invoke.MethodHandle实例的解析结果REF_getStatic,REF_putStatic,REF_invokeStatic句柄对应的类没有初始化,则进行初始化
那么被动使用就是除以上七种使用方式以外的其他方式都是属于被动使用,并且被动使用是不会导致类的初始化的。所有的Java虚拟机实现都是在每个类或接口被Java程序“首次主动使用”时才初始化他们,并且只会被初始化一次。