一道面试题:考察类的初始化顺序

题目:

public class Test{

    public static int k = 0;

    public static Test t1 = new Test("t1");

    public static Test t2 = new Test("t2");

    public static int i = print("i");

    public static int n = 99;

    private int a = 0;

    public int j = print("j");

    {

        print("构造代码块");

    }

    static{

        print("静态代码块");

    }

    public Test(String str){

        System.out.println((++k)+":"+str+"  i="+i+"  n="+n);

        ++i;

        ++n;

    }

    private static int print(String str){

        System.out.println((++k)+":"+str+"  i="+i+"  n="+n);

        ++n;

        return++i;

    }

    public static void main(String[] args) {

        Test t = new Test("init");

    }

}

输出结果为:

1:j  i=0  n=0

2:构造块  i=1  n=1

3:t1  i=2  n=2

4:j  i=3  n=3

5:构造块  i=4  n=4

6:t2  i=5  n=5

7:i  i=6  n=6

8:静态块  i=7  n=99

9:j  i=8  n=100

10:构造块  i=9  n=101

11:init  i=10  n=102

分析:

1、声明静态变量,并赋值为变量类型默认值:k=0    t1=null    t2=null    i=0    n=0。

2、初始化静态变量:k=0。

3、初始化静态变量:t1=new Test("t1")。此处实例化Test类时,会先定义非静态变量:a=0    j=0,紧接着,初始化非静态变量:a=0    j=print("j"),此处对j初始化时调用print方法,输出之前,k先自增,k=1,而后输出:1:j  i=0  n=0,同时,i=1    n=1。回到执行t1=new Test("t1"),调用Test构造方法前,先执行构造代码块,构造代码块调用print方法,输出之前,k先自增,k=2,而后输出:2:构造块  i=1  n=1 ,同时,i=2    n=2。继续执行t1=new Test("t1"),调用Test构造方法,输出之前,k先自增,k=3,而后输出:3:t1  i=2  n=2,同时,i=3    n=3。

4、初始化静态变量:t2=new Test("t2"),步骤同3。此处实例化Test类时,会先定义非静态变量:a=0    j=0,紧接着,初始化非静态变量:a=0    j=print("j"),此处对j初始化时调用print方法,输出之前,k先自增,k=4,而后输出:4:j  i=3  n=3,同时,i=4    n=4。回到执行t2=new Test("t2"),调用Test构造方法前,先执行构造代码块,构造代码块调用print方法,输出之前,k先自增,k=5,而后输出:5:构造块  i=4  n=4,同时i=5    n=5。继续执行t2=new Test("t2"),调用Test构造方法,输出之前,k先自增,k=6,而后输出:6:t2  i=5  n=5,同时i=5    n=5。

5、初始化静态变量:i=print("i")。调用print方法,输出之前,k先自增,k=7,而后输出:7:i  i=6  n=6,同时i=7    n=7。

6、初始化静态变量:n=99。

7、按照声明顺序,执行静态代码块:静态代码块调用print方法,输出之前,k先自增,k=8,而后输出:8:静态块  i=7  n=99,同时,i=8    n=100。

8、此时,静态变量初始化和静态代码块执行已完成。继续声明非静态变量,并赋值为变量类型默认值:a=0    j=0。

9、初始化非静态变量:a=0。

10、初始化非静态变量:j=print("j")。此处对j初始化时调用print方法,输出之前,k先自增,k=9,而后输出:9:j  i=8  n=100,同时,i=9    n=101。

11、此时,Test的加载已完成,继续执行Main方法中Test t=new Test("init")。调用Test构造方法前,先执行构造代码块,构造代码块调用print方法,输出之前,k先自增,k=10,而后输出:10:构造块  i=9  n=101,同时i=10    n=102。继续执行t=new Test("init"),调用Test构造方法,输出之前,k先自增,k=11,而后输出:11:init  i=10  n=102,同时i=11    n=103。

总结:

如存在类的继承:

1、先进行父类静态变量初始化和静态代码块执行,两者的执行顺序取决于声明的顺序。

2、再进行子类静态变量初始化和静态代码块执行,两者的执行顺序取决于声明的顺序。

3、再进行父类非静态变量初始化和非静态代码块执行,两者的执行顺序取决于声明的顺序。

4、再进行父类构造方法执行。

5、再进行子类非静态变量初始化和非静态代码块执行,两者的执行顺序取决于声明的顺序。

6、再进行子类构造方法执行。

7、静态代码块只在类加载时执行一次,构造代码块在每次调用类的构造方法实例化时都会执行一次。

以上,概括为:先子类后父类,先静态后非静态,先属性后方法,先声明后赋值。

你可能感兴趣的:(一道面试题:考察类的初始化顺序)