虚拟机类加载机制
@(Java虚拟机)[类加载]
[TOC]
类加载时机
类加载到卸载的生命周期包括:
- 加载(Loading)
- 验证(Verification)
- 准备(Preparation)
- 解析(Resolution)
- 初始化(Initialization)
- 使用(Using)
- 卸载(Unloading)
其它阶段按步执行,但解析阶段不一定在初始化后。可能在初始化之后或者交差。为的是支持Java语言的运行时绑定(动态绑定或晚期绑定)。
对类的第一个阶段:加载,虚拟机没有强制约束,但是对于初始化阶段,虚拟机规定了有且仅有5种情况必须立即对类进行"初始化"。其他过程在此之前。
- 遇到new,getstatic,putstatic或invokestatic字节码指令时,如果类没有初始化则必须先初始化。4个指令最常见的场景是:使用new关键字实例化对象的时候,读取或设置一个类的静态字段(被final修饰,已在编译器把结果放入常量池的静态字段除外)的时候,以及调用一个类的静态方法的时候。
- 使用reflect包的方法对类进行反射调用的时候,没有初始化则先初始化。
- 初始化类时发现其父类还没有进行初始化。
- 虚拟机启动时,用户需指定一个要执行的主类(main()),虚拟机先初始化这个类。
- 当使用jdk1.7的动态语言支持时,如果MethodHandle实例最后解析结果REF_getStatic,REF_putStatic,REF_invokeStatic的方法句柄,并且这个方法的句柄对应的类没有初始化。
这5种行为称为对一个类进行主动引用。被动引用举例:
public class Test2 {
public static void main(String[] args) throws InterruptedException {
//1.通过子类引用父类的静态字段,不会导致子类初始化。
//输出结果为
//SuperClass init
//3
System.out.println(SubClass.value);
//2.数组定义,不会触发
SuperClass[] subClasses=new SuperClass[10];
//3.value如果为常量,都不会初始化
//输出结果为
//3
System.out.println(SubClass.value);
}
}
class SuperClass {
public final static int value=3;
public static int value=3;
static {
System.out.println("SuperClass init");
}
}
class SubClass extends SuperClass{
static {
System.out.println("SubClass init");
}
}
类加载过程
加载
在加载过程中,虚拟机需要完成的:
- 通过类的全限定名来获取定义此类的二进制字节流
- 将这个字节流代表的静态存储结构转为方法区的运行时数据结构
- 在内存中生成一个Class对象对应这个类。
网友评论