刷头条的时候看到了这个:
以前也看到过,应该是阿里的校招笔试题,当时懒得理这种工作中毫无意义的东西。
今天突然来了兴趣,就想看看能不能靠自己的知识来理清其中的逻辑,结果还不错,(*^_^*)。
原题略绕,不直观,先来个精简版:
1 public class A { 2 static{ 3 System.out.println("我是静态代码块"); 4 } 5 6 { 7 System.out.println("实例代码块"); 8 } 9 10 public A(){11 System.out.println("构造方法");12 }13 14 public static void main(String[] args){15 new A(); //放开注释,执行,看一下实例代码块和构造方法的执行顺序16 }17 }
上面的代码,直接执行,即可观察到创建实例时的加载执行顺序。
执行结果如下:
我是静态代码块实例代码块构造方法
很明显,一般情况下,创建实例的执行顺序就是:静态代码块 > 实例代码块 > 构造方法。
不知道你们有没有考虑过,为什么要按照这种顺序来?
其实很简单,要满足依赖前置条件!
第一点:因为静态变量的可以被直接调用,所以静态变量部分必须先加载并创建;
第二点:因为静态代码块是在所有静态变量加载完毕后一次性执行的,所以其执行要晚于所有静态变量的加载;
第三点:实例代码块是在创建实例的时候执行的,确切的说,是在实例的内存空间分配完毕,而在构造进行之前执行的。-- 如果学过C++,你应该知道这个。
OK,已经有了上面三点,那我们再来推一下该面试题中的情况。
还是先用简化版本,方便看懂:
public class A { private static A a = new A(); //静态实例变量 static{ System.out.println("我是静态代码块"); } { System.out.println("实例代码块"); } public A(){ System.out.println("构造方法"); } //TODO 执行空的main方法,就是只加载字节码。可以有效测试加载过程中的顺序。 public static void main(String[] args){ // new A(); //放开注释,执行,看一下实例代码块和构造方法的执行顺序 }}
相对于前面那一版,这里只增加了一个本类的静态实例变量 a 。当然还注释掉了main方法中的 new A(),因为我们不需要额外的实例创建来干扰观察。
执行main方法,结果如下:
实例代码块构造方法我是静态代码块
用上面三条依赖前置条件推理一下看看:
①先创建静态实例变量,结果执行new A();②而创建实例必然导致实例代码块的先执行,再执行构造代码块!
③执行完构造代码块,静态实例变量a就构造完毕,此时所有静态变量构建完毕,于是执行静态代码块!
原文中有多个静态变量、静态实例变量,静态实例变量的创建还会修改静态变量,让推理每一步静态变量的值。
其实再加上一条即可推理出来:按照声明顺序加载。
总之,虽然知道了原理,但是很烦这种推理题 - 把人搞得晕晕的。