龙珠

修炼自己与发现世界

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.");
    }
                           
                       
}

求输出的结果。

在初始化过程中,有以下几个原则:

  1. 静态static变量优先初始化,且只执行一次!另外,static变量之间是顺序执行;之后才执行main函数。

  2. new一个新的对象的时候,先对非static的变量和构造块进行初始化,之后再执行对象内的执行语句。这是每次new一个新对象时均对其内部的非static变量进行初始化。

  3. 若使用到的某变量是在后面语句中才赋值,则先使用系统默认值(如代码中n最开始使用0,直至执行到赋值为99的语句)。

有了这些原则,我们可以写出执行结果:

一、先顺序执行static语句(原则1)

  1. 运行第5行“静态块【1】”(原则1),输出k=1(!!注意:此时第7行代码还未执行,k还没有初始化,因此采用默认值为0),i=0(原则3),n=0(原则3);

  2. 运行第7行,无输出(注意!第5行中已经使用++k,之后k为1。但在此处k重新复制为0,虽然无输出,但之后的k是从新由0算起的);

  3. 运行第8行,new一个t1(原则2):先初始化t1内部的非static变量,包括13~17行的c、j和构造块。分别输出“c”、“j”和“构造块”;之后,执行构造函数内的语句,输出“t1”。此处,k、i、n均逐次加1;

  4. 运行第9行,new一个t2(原则2):同上。分别输出“c"、“j”、“构造块”和“t2”;

  5. 运行第11行,输出“i”。

  6. 运行第12行,n的值改为99(之前输出的n初始为0,之后输出的n才是为99);

  7. 第13~18行只有在new新对象的时候才输出,此处无输出。

  8. 运行第20行,输出“静态块【2】”;

之后无static变量代码,对static变量的初始化结束。

二、执行main函数

  1. main函数中先输出“Begin to init...”;

  2. 之后,new一个新的对象(原则2)。先输出“c”、“j”、“构造块”,在输出“init”;

  3. 最后输出“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.)