Java类中的初始化顺序

时间:2021-07-10 19:43:40

根据《Thinking in Java》相关章节及自己的理解举例来说明类初始化顺序。

public class InitialOrder {

private static String staticField = "Static Field Initial";

private String field = "Field Initial";

static {
System.out.println(staticField);
System.out.println("Static Patch Initial");
}

{
System.out.println(field);
System.out.println("Field Patch Initial");
}

public InitialOrder() {
System.out.println("Structure Initial ");
}

public static void main(String[] argc) {
new InitialOrder();
}
}

Static Field Initial (静态变量)
Static Patch Initial (静态初始化块)
Field Initial (变量)
Field Patch Initial (初始化块)
Structure Initial (构造器)

public class ParentInitialOrder {
private static String staticField = "Parent Static Field Initial";

private String field = "Parent Field Initial";

static {
System.out.println(staticField);
System.out.println("Parent Static Patch Initial");
}

{
System.out.println(field);
System.out.println("Parent Field Patch Initial");
}

public ParentInitialOrder() {
System.out.println("Parent Structure Initial ");
}

}

public class ChildInitialOrder extends ParentInitialOrder {
private static String staticField = "Child Static Field Initial";

private String field = "Child Field Initial";

static {
System.out.println(staticField);
System.out.println("Child Static Patch Initial");
}

{
System.out.println(field);
System.out.println("Child Field Patch Initial");
}

public ChildInitialOrder() {
System.out.println("Child Structure Initial ");
}

public static void main(String argv[]) {
new ChildInitialOrder();
}
}

Parent Static Field Initial
Parent Static Patch Initial
Child Static Field Initial
Child Static Patch Initial
Parent Field Initial
Parent Field Patch Initial
Parent Structure Initial
Child Field Initial
Child Field Patch Initial
Child Structure Initial

测试题:

public class InitialOrderTest {
public static int k = 0;
public static InitialOrderTest t1 = new InitialOrderTest("t1");
public static InitialOrderTest t2 = new InitialOrderTest("t2");
public static int i = print("i");
public static int n = 99;
public int j = print("j");

static {
print("静态块");
}

{
print("构造块");
}

public InitialOrderTest(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);
++n;
return ++i;
}

public static void main(String[] args) {
// TODO Auto-generated method stub
InitialOrderTest t = new InitialOrderTest("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、我们要调用InitialOrderTest类的static方法main,所以JVM会在classpath中加载InitialOrderTest.class,然后对所有static的成员变量进行默认初始化。这时k、i、n被赋值为0,t1、t2被赋值为null。
2、又因为static变量被显式赋值了,所以进行显式初始化,当对t1进行显式赋值时,用new的方法调用了Alibaba的构造函数,所以这次需要对t1对象进行初始化。因为InitialOrderTest所有static部分已经在第一步中初始化过了(虽然第一步中还没有执行static块,但在初始化t1时也不会去执行static块,因为JVM认为这次是第二次加载InitialOrderTest这个类了,所有的static部分都会被忽略掉),所以这次直接初始化非static部分。于是有了

1:j i=0 n=0
2:构造块 i=1 n=1
3:t1 i=2 n=2

接着对t2进行赋值,过程与t1相同

4:j i=3 n=3
5:构造块 i=4 n=4
6:t2 i=5 n=5

t1、t2这两个static成员变量赋值完后到了static的i与n,于是有了下面的输出:

7:i i=6 n=6

到现在为止,所有的static的成员变量已经被第二次赋值过了,下面到static块了

静态块 i=7 n=99

至此,所有的static部分赋值完毕了,下面开始执行main方法里面的内容,因为main方法的第一行就又用new的方式调用了InitialOrderTest的构造函数,所以其过程与t1、t2类似

9:j i=8 n=100
10:构造块 i=9 n=101
11:init i=10 n=102