Java:构造块和静态块初始化顺序
昨天阿里笔试题中有一道考static和构造块的初始化顺序的,当时没做出来,对static的了解还是不够,今天调试了下题目代码(有略微修改,不影响)如下:
package test; public class TestStatic { static{ print("静态块【1】"); } public static int k=0; public static TestStatic t1 = new TestStatic("t1"); public static TestStatic t2 = new TestStatic("t2"); public static int i=print("i"); public static int n=99; public int c = print("c"); public int j=print("j"); { print("构造块"); } static{ print("静态块【2】"); } public TestStatic(String str){ System.out.println((++k)+":"+str+" i="+i+" n="+n); ++i; ++n; } public static int print(String str){ System.out.println((++k)+":"+str+" i="+i+" n="+n); ++i; return ++n; } public static void main(String[] strings){ System.out.println("Begin to init..."); TestStatic t = new TestStatic("init"); System.out.println("Init Done."); } }
求输出的结果。
在初始化过程中,有以下几个原则:
静态static变量优先初始化,且只执行一次!另外,static变量之间是顺序执行;之后才执行main函数。
new一个新的对象的时候,先对非static的变量和构造块进行初始化,之后再执行对象内的执行语句。这是每次new一个新对象时均对其内部的非static变量进行初始化。
若使用到的某变量是在后面语句中才赋值,则先使用系统默认值(如代码中n最开始使用0,直至执行到赋值为99的语句)。
有了这些原则,我们可以写出执行结果:
一、先顺序执行static语句(原则1)
运行第5行“静态块【1】”(原则1),输出k=1(!!注意:此时第7行代码还未执行,k还没有初始化,因此采用默认值为0),i=0(原则3),n=0(原则3);
运行第7行,无输出(注意!第5行中已经使用++k,之后k为1。但在此处k重新复制为0,虽然无输出,但之后的k是从新由0算起的);
运行第8行,new一个t1(原则2):先初始化t1内部的非static变量,包括13~17行的c、j和构造块。分别输出“c”、“j”和“构造块”;之后,执行构造函数内的语句,输出“t1”。此处,k、i、n均逐次加1;
运行第9行,new一个t2(原则2):同上。分别输出“c"、“j”、“构造块”和“t2”;
运行第11行,输出“i”。
运行第12行,n的值改为99(之前输出的n初始为0,之后输出的n才是为99);
第13~18行只有在new新对象的时候才输出,此处无输出。
运行第20行,输出“静态块【2】”;
之后无static变量代码,对static变量的初始化结束。
二、执行main函数
main函数中先输出“Begin to init...”;
之后,new一个新的对象(原则2)。先输出“c”、“j”、“构造块”,在输出“init”;
最后输出“Init Done.”
执行完毕。最后运行代码结果如下:
1:静态块【1】 i=0 n=0 1:c i=1 n=1 2:j i=2 n=2 3:构造块 i=3 n=3 4:t1 i=4 n=4 5:c i=5 n=5 6:j i=6 n=6 7:构造块 i=7 n=7 8:t2 i=8 n=8 9:i i=9 n=9 10:静态块【2】 i=10 n=99 Begin to init... 11:c i=11 n=100 12:j i=12 n=101 13:构造块 i=13 n=102 14:init i=14 n=103 Init Done.
(对k的初始赋值请注意第1行和第2行k的位置输出均为1.)