类初始化时机
遇到new ,getstatic,putstatic,或invokestatic 这4条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。
这4条指令最常见的java代码场景是:
使用new关键字实例化对象的时候。
读取或设置一个类的静态字段(被final修饰,已在编译期把结果放入常量池的静态字段除外)
使用java.lang.reflect包的方法对类进行反射调用时候,如果类没有进行过初始化,则需要先触发其初始化。
当被始化一个类的时候,如果发现其父类还没初始化,则先触发其父类初始化。
(接口除外,接口在初始化时,并不要求其父接口全部都完成了初始化,只有在真正使用父接口的时候才会初始化)
包含main方法的执行类。
对于上面这4种会触发类进行初始化的行为,称为对一个类进行主动引用。
除此之外,所有引用类的方式都不会触发初始化,称为被动引用。
下面是被动引用的三个例子。
public class SuperClass { static { System.out.println("super class init"); } public static int value=123; }
public class SubClass extends SuperClass{ static { System.out.println("sub class init"); } }
/** * 非主动引用类的字段演示 */ public class NotInitialization { public static void main(String[] args) { System.out.println(SubClass.value); } }
输出结果:
super class init
123
-----------------------------------------------------------------
package com.phl.reference.passive;
/** * 非主动引用:通过数组来引用,不会触发类的初始化 */ public class NotInitialization2 { public static void main(String[] args) { SuperClass [] scs=new SuperClass[10]; //没有输出 } } 这里没有输出,说明没有触发类com.phl.reference.passive.SuperClass的初始化 ; 但是这段代码触发另外一个类名为 [com.phl.reference.passive.SuperClass 的初始化, 对于用户来说,这并不是一个合法的类名称,这是由虚拟机自动生成的。-------------------------------------------------public class ConstantClass { static { System.out.println("ConstantClass class init"); } public static final String HELLOWORD="hello world"; }/** * 常量在编译阶段会存入调用类的常量池中,本质上没有直接引用定义常量的类ConstantClass,因此不会被触发类的初始化NotInitialization3
其实就是在编译阶段ConstantClass.HELLOWORD已经被替换了,替换的值放在NotInitialzaion3的常量池中
*/public class NotInitialization3 { public static void main(String[] args) { System.out.println(ConstantClass.HELLOWORD); // 不会输出"ConstantClass class init" }}