虚拟机规范规定有且只有如下几种情况【主动引用】下必须立即对类进行初始化:
1》使用new实例化对象、读取或设置类的静态字段(final修饰除外,编译期已放入常量池)、调用静态方法
2》使用java.lang.reflect包的方法对类进行发射调用时,若没有初始化必须立即初始化
3》初始化类的时候,如果父类还没初始化必须先初始化父类
一个接口在初始化时,并不要求其父类接口全部完成初始化,只有在真正使用到父类接口的时候(如引用接口中定义的常量)才会初始化
4》虚拟机启动时包含main方法的主类需要初始化
5》使用jdk1.7的动态语言支持时,如果一个java.lang.invoke.MethodHandler实例最后的解析结果REF_getStatic,
REF_outStatic,REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化
注:下面情况【被动引用】不会触发类的初始化
1》通过子类引用父类的静态字段,子类不会触发初始化
2》通过数组定义引用类,不会触发类的初始化
3》引用其他类的常量不会触发相应类的初始化
初始化过程
类的初始化实际上是执行了一个类构造器方法的过程,此处的clinit不是类的构造函数(init())
clinit()方法是类由编译器自动收集类中所有类变量的赋值动作和静态语句块中的语句合并产生的,
编译器收集的顺序是语句在源文件中出现的顺序。注:静态语句块只能访问到定义在静态语句块之前的变量,定义在它之后的变量,
可以在前面的静态语句块赋值,但不能访问
public class Test1 {
static {
t = 10;//编译可以正常通过
System.out.println(t);//提示illegal forward reference错误
}
static int t = 0;
}