类初始化
一.主动引用:
- 遇到new、getstatic、putstatic或者invokestatic这4条字节指令,如果类没有被初始化过,则会触发类的初始化。也就是说下列情况:
- new关键字实例化对象
- 读取或者设置一个类的静态字段(静态常量除外)
- 调用一个类的静态方法
- 使用java.lang.reflect包的方法对类进行反射调用的时候。如果类没有被初始化过,则会触发类的初始化。
- 当初始化一个类的时候,发现其父类还未初始化,则先触发父类的初始化。
- 虚拟机启动时,先初始化主类。
二.被动引用:
1.子类引用父类的静态变量,不会引起子类的初始化.
对于静态字段,只有直接定义这个字段的类才会进行初始化。
public class SuperClass{
static{
System.out.println("SuperClass init...");
}
public static int value = 123;
}
public class SubClass extends SuperClass{
static{
System.out.println("SubClass init...");
}
}
public class Test{
public static void main(String[] args){
System.out.println(SubClass.value);
}
}
输出结果为: SuperClass init…
2.对常量的引用,不会引起初始化。
因为常量在编译的时候已经将常量放入调用类的常量池里面。假如A调用B的常量c,经过编译后,常量c已经是A常量池中的常量,Class文件中没有两个类关联的信息,也就是在编译后AB没有任何联系,所以不会引起初始化。
public class ConstClass{
static{
System.out.println("ConstClass init...");
}
public static final String S = "Const";
}
public class Test{
public static void main(String[] args){
System.out.println(ConstClass.S);
}
}
没有任何输出结果。
3.通过数组定义来引用类,不会触发初始化。
虽然不会初始化我们定义的类,但是会初始化一个由字节码指令newarray触发生成的一个类。
public class ArrayTest{
static{
System.out.println("ArrayTest init...");
}
}
public class Test{
public static void main(String[] args){
ArrayTest[] array = new ArrayTest[5];
}
}
没有任何输出结果。
三.针对接口的说明
主要不同点是,类在初始化的时候要求其父类都初始化过。而接口在初始化的时候并不要求父类接口初始化,只有在真正用到父接口的时候才初始化。