类的生命周期
类的加载,连接,初始化,使用,卸载
其中类加载的过程包括了加载,验证,准备,解析,初始化五个阶段,除了解析外其余四个是固定顺序的,解析可以发生在初始化后。这是为了支持JAVA语言运行时绑定。注意这几个阶段只是开始时间是固定的,不是按顺序完成。
类的加载:
加载是类加载过程的第一个阶段,在加载阶段,虚拟机需要完成以下三件事情:
- 通过一个类的全限定名来获取其定义的二进制字节流。
- 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
- 在Java堆中生成一个代表这个类的java.lang.Class对象,作为对方法区中这些数据的访问入口。
简单来说就是将class文件在方法区中创建类的数据结构,在堆中创建对象并作为访问方法的入口
验证
验证是连接阶段的第一步,这一阶段是确保我们的class文件的字节流中包含的信息符合当前虚拟机的要求,且不会危害到自身的安全。验证阶段大概分为四个阶段的检验动作
- 文件格式验证:验证字节流是否符合Class文件格式规范,例如: 是否以0xCAFEBABE开头、主次版本号是否在当前虚拟机的处理范围之内、常量池中的常量是否有不被支持的类型。
- 原数据验证:对字节码描述的信息进行语义分析,保证其符合JAVA规范
- 字节码验证:通过数据流和控制流分析,确定程序语义是合法的,符合逻辑的
- 符号引用验证:确保解析动作能正确运行
准备
准备阶段是为类的静态变量分配内存,并为其初始化默认值。
这些内存都在方法区里分配
- 这时候进行分配的仅包括类变量(static),而不包括实例变量,实例变量会在对象实例化的时候一起分配在Java堆中。
- 这里所设置的初始值通常情况下是数据类型默认的零值(如0、0L、null、false等),而不是被在Java代码中被显式地赋予的值。
解析
解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程,解析动作主要针对类或接口,字段,类方法,接口方法,方法类型,方法句柄和调用点限定符七类符号引用进行。符号引用就是一组符号来描述目标,可以是任何字面量。
初始化
初始化,为类的静态变量赋正确的初始值,JVM负责对类进行初始化
在Java中对类变量进行初始值设定有两种方式:
- 声明类变量是指定初始值
- 使用静态代码块为类变量指定初始值
类初始化的时机
- 创建类的实例,也就是 new 一个对象
- 访问某个类或接口的静态变量,或者对该静态变量赋值
- 调用类的静态方法
- 反射(Class.forName)
- 初始化某个子类,那他的父类也会被初始化
- Java虚拟机启动时,被标注为启动类的类,直接用Java.exe命令来运行某个类
使用:
类访问方法区的数据结构的接口,对象是Heep区的数据
卸载:
Java虚拟机将结束生命的几种情况
- 执行了System.exit()方法
- 程序正常执行结束
- 程序执行过程中遇到错误异常终止
- 由于操作系统错误导致Java虚拟机停止工作