虚拟机加载时机

来源:互联网 发布:专升本远程网络教育 编辑:程序博客网 时间:2024/05/22 05:32

类从加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:
加载的生命周期

从这个图中可以看出,虚拟机的加载顺序,其中加载,验证,准备,初始化和卸载的顺序的确定的,类的加载过程必须按照这个顺序开始,而解析就不一定。他可能在初始化阶段之后再开始,这是为了支持Java语言的运行时动态绑定设计的。

那什么情况下需要进行类的加载呢?Java虚拟机并没有进行强制的规定。在虚拟机规范中对于类强制初始化有5种情况(而加载,验证,准备自然都在此阶段之前开始),那么哪几种情况需要主动初始化呢?

a:遇到new,getstatic,putstatic,invokestatic这4个指令的时候,如果类还没有经过初始化,则需要触发类的初始化操作。生成这4个指令的常见场景是:使用new关键字实例化一个对象,读取或者设置一个静态的字段以及调用一个类的静态方法的时候。

b:使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有初始化,就先触发其初始化。

c:当初始化一个类的时候,如果发现其父类没有初始化的时候,先初始化其父类。

d:当虚拟机启动的时候,用户需要一个指定的执行的方法(java中是Main方法),虚拟机先初始化这个类。

e:当使用JDK1.7的时候,如果java.lang.invoke.MethodHandle实例的解析结果是REF_getStatic, REF_pusStatic,REF_invokeStatic的方法句柄,并且这个句柄的类没有被初始化,则需要先初始化这个类。

对于以上的5中触发类的初始化的场景,虚拟机规范中有一个强烈的限定语,“有且只有”,这5中场景中的行为成为对一个类的主动引用,初次之外,所有引用类的方式都不会触发初始化,称为被动引用。下面三种方式都是类的被动引用。

a:通过子类引用父类的静态字段,不会导致子类的初始化。
这是子类和父类

这是一个main方法

这是上面的运行的结果

b:通过定义数组来引用类,不会触发类的初始化(new一个对象,会触发类的初始化)。
在控制台中没有打印出初始化的语句

c:常量在编译阶段就存入到了类的常量池中,本质上并没有直接引用到定义在常量中的类,因此也不会进行类的初始化。就是在类中定义一个public static final String name=“hello”是不会初始化这个类的。

原创粉丝点击