上代码:
public class InitialOrder {
private static int i = 2;
private static InitialOrder obj = new InitialOrder();
public InitialOrder() {
i ++;
}
public static void main(String[] args) {
System.out.println(InitialOrder.i);
}
}
情况1:如果按照上面代码,直接运行,打印结果为 3。读者可以试一试。
情况2:第一个属性和第二个属性代码顺序调换一下,打印结果为 2。
这就和class文件的加载过程有关系了。
class文件加载过程:class加载 → verification → prepare → resolve → initializing
主要说说 prepare 和 initializing阶段。
prepare:主要是给静态属性赋值。
initializing:主要是给实例赋值。
分析情况1:在main方法中打印 i 的值时,首先java文件需要编译成class文件,加载的class文件需要经过class文件格式的验证,然后进入静态属性初始化阶段,这个时候 i = 0,obj = null。再进入resolve阶段把符号引用解析为直接引用,进入到 initializing 阶段,需要给实例初始化值,这个时候先初始化 i = 2 ,再初始化 obj = new InitialOrder() ,obj 生成对象的时候调用了构造函数,构造函数中有 i++ 操作,原本 i = 2,i ++ 指令执行后,i = 3。所以情况1打印结果为3。
分析情况2:加载class文件到prepare阶段时,静态属性赋值,obj = null,i = 0,加载到 initializing 阶段,obj = new InitialOrder(),obj 生成对象的时候调用了构造函数,构造函数中有 i++ 操作,原本 i = 0,i ++ 指令执行后,i = 1。按照代码顺序给 i 赋值,这个时候又把 2 赋值给 i 。所以打印结果为 2。