Java类初始化之clinit
初始化阶段就是执行类构造器<clinit>()
方法的过程。<clinit>()
并不是程序员在Java代码中直接编写的方法,而是Javac编译器的自动生成物。
<clinit>()
方法是由编译器自动收集类中的所有类变量赋值动作和静态语句块(static{}
)中的语句合并产生的,收集顺序是按在源文件中的出现顺序决定的。静态语句块中只能访问到定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块中可以赋值,但不能访问。
public class Test{
static{
i = 0; //给变量赋值可以编译通过
System.out.println(i); //非法向前引用
}
static int i = 1;
}
<clinit>()
方法与类的构造函数(在虚拟机视角中的实例构造器<init>()
方法)不同,它不需要显式地调用父类构造器,Java虚拟机会保证子类的<clinit>()
方法执行器前,父类的<clinit>()
方法已经执行完毕。因此,在Java虚拟机中第一个被执行的<clinit>()
方法的类型肯定就是java.lang.Object。
由于父类的<clinit>()
方法先执行,也就意味着父类中定义的静态语句块优先于子类的变量赋值操作。
static class Parent{
public static int A = 1;
static{
A = 2;
}
}
static class Sub extends Parent{
public static int B = A;
}
public static void main(String[] args){
System.out.println(Sub.B);
}