类的生命周期
类的生命周期:描述一个类加载、使用、卸载的整个过程。
主要分为五个大的阶段:加载、链接、初始化、使用、卸载。
其中连接可以分为三个小阶段:验证、准备、解析。
加载
1.加载(Loading)阶段的第一步是类加载器根据类的全限定名通过不同的渠道以二进制的方式获取字节码信息。
2.类加载器在加载完类之后,Java虚拟机会将字节码中的信息保存方法区中。
3.类加载器在加载完类之后,Java虚拟机会将字节码中的信息保存内存的方法区中。
生成一个InstanceKlass,保存类的所有信息,里面还包含实现特定功能比如多态的信息。
4.同时Java虚拟机会在堆中生成一份与方法区中数据类似的java.long.Class对象
作用是在Java代码中去获取类的信息以及存储静态字段的数据(JDK8之后)
连接
连接主要分为三个小阶段:验证、准备、解析。
验证:主要目的验证JAVA字节码文件是否遵守《JAVA虚拟机规范》
校验的主要内容如下:
1.文件格式验证,比如文件是否以OxCAFEBABE开头,主次版本号是否满足当前Java虚拟机版本要求。
2.元信息验证,例如类必须有父类(super不能为空)。
3.验证程序执行指令的语义,比如方法内的指令执行到一半强行跳转到其他方法中去。
4.符号引用验证,例如是否访问了其他类中private的方法等。
校验案例
准备阶段:静态(static)变量分配内存并设置初始值。
final修饰的基本数据类型的静态变量,准备阶段将代码中的值进行赋值.
解析
解析阶段主要将常量池中的符号引用替换为直接引用
直接引用不在使用编号,而是使用内存中的地址进行访问数据
初始化阶段
1.初始化阶段会执行静态代码块中的代码,并为静态变量赋值.
2.初始化阶段会执行字节码中的clinit部分的字节码指令
以下几种方式会导致类的初始化:
1.访问一个类的静态变量或者静态方法,注意变量是final修饰的并且等号右边是常量不会触发初始化。
2.调用Class.forName(String className)。
3.new一个该类的对象时。
4.执行Main方法的当前类。
举例
1.访问一个类的静态变量或者静态方法,注意变量是final修饰的并且等号右边是常量不会触发初始化。
测试代码
添加vm参数用于打印
输出结果
修改为final后不进行初始化
2.调用Class.forName(String className)。
3.new一个该类的对象时
相关笔试题
clinit指令在特定情况下不会出现:
1.无静态代码块且无静态变量赋值语句。
2.有静态变量的声明,但是没有赋值语句。
public static int i;
3.静态变量的定义使用final关键字,这类变量会在准备阶段直接进行初始化。
public static final int i=10;
相关笔试题
1.
2.
3.
4.