Earth Guardian

You are not LATE!You are not EARLY!

0%

Java 代码执行顺序

Java 代码执行顺序:main 方法,类初始化过程,类实例化过程。

main 方法

规则

  • 如果当前类作为 Java 程序运行,则 main 是程序的入口方法
  • 如果当前类仅仅作为类实例,则 main 方法和普通 static 方法一样,只有主动调用时才会执行

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// 1. 程序入口
public class TestMajorMain {
public void major(){
System.out.println("TestMajorMain, major function.");
}

public TestMajorMain(){
System.out.println("TestMajorMain, Constructor.");
}

public static void main(String[] args) {
System.out.println("TestMajorMain, main.");
TestMinorMain minorMain = new TestMinorMain();
minorMain.minor();
}
}

// 2. 仅作为类实例
public class TestMinorMain {

public void minor(){
System.out.println("TestMinorMain, minor function.");
}

public TestMinorMain(){
System.out.println("TestMinorMain, Constructor.");
}

public static void main(String[] args) throws InterruptedException {
System.out.println("TestMinorMain, main.");
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
while (true){

}
}
});
thread.start();

Thread.sleep(100);

thread.join();
System.out.println("TestMinorMain, quit.");
}
}

// 3. 执行 TestMajorMain 后的结果
TestMajorMain, main.
TestMinorMain, Constructor.
TestMinorMain, minor function.

Java 代码执行顺序

执行顺序理论基础,参考:Java 类加载机制

规则

  • 类初始化过程:静态成员,静态代码块
  • 类实例化过程:即调用构造方法生成实例时
    • 普通成员,构造块
    • 然后构造方法

类初始化过程中,可能调用了实例化过程(因为 static 可以修饰方法,属性,代码块,内部类),此时则会暂停类初始化过程而先执行实例化过程(被打断),执行结束后再进行类初始化过程。

示例

下面就是典型的暂停类初始化示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class TestExecSequence {
public static int k = 0;
public static TestExecSequence t1 = new TestExecSequence("t1");
public static TestExecSequence t2 = new TestExecSequence("t2");
public static int i = print("i");
public static int n = 99;
public int j = print("j");

{
print("constructor code block.");
}

static {
print("static code block.");
}

public TestExecSequence(String str) {
System.out.println("###### TestExecSequence Constructor *******");
System.out.println((++k) + ":" + " i=" + i + " n=" + n + " " + str);
++i;
++n;
}

public static int print(String str) {
System.out.println((++k) + ":" + " i=" + i + " n=" + n + " " + str);
++n;
return ++i;
}

public static void main(String args[]) {
System.out.println("****** TestExecSequence main #####");
TestExecSequence t = new TestExecSequence("main t");
}
}

// Result
1: i=0 n=0 j
2: i=1 n=1 constructor code block.
###### TestExecSequence Constructor *******
3: i=2 n=2 t1
4: i=3 n=3 j
5: i=4 n=4 constructor code block.
###### TestExecSequence Constructor *******
6: i=5 n=5 t2
7: i=6 n=6 i
8: i=7 n=99 static code block.
****** TestExecSequence main #####
9: i=8 n=100 j
10: i=9 n=101 constructor code block.
###### TestExecSequence Constructor *******
11: i=10 n=102 main t

所有成员变量在初始化前都是默认初始值。

代码解析:

  • 成员变量默认值:k = i = n = j = 0
  • 代码顺序执行,初始化 k = 0
  • 出现类初始化暂停,t1 执行实例化过程
  • t1 实例化过程中,先执行成员变量初始化 j,再执行构造代码块,最后执行构造方法
  • t1 实例化完后,恢复类初始化过程,接着遇到了 t2 实例化,继续暂停类初始化,执行 t2 实例化过程
  • t1 实例化一样,依次初始化 j,构造代码块,构造方法
  • 恢复类初始化,静态成员变量初始化 in = 99
  • 继续类初始化,执行静态代码块
  • 所有静态成员和静态代码块执行完后,进入程序 main 方法
  • main 中,实例化 t ,依次执行初始化 j,构造代码块,构造方法

子类实例化顺序

规则

子类实例化时会先实例化父类,代码执行顺序基本上参考上面的规则,但是父类先执行,具体如下:

  • 父类类初始化过程:静态成员变量,静态代码块
  • 子类类初始化过程:静态成员变量,静态代码块
  • 父类类实例化过程:普通成员变量,构造代码块,最后父类的构造方法
  • 子类类实例化过程:普通成员变量,构造代码块,最后子类的构造方法

static 静态成员变量和方法是属于类的,所以只会在类初始化时初始化或执行一次,类在多次实例化时不会重复执行。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// 1. Father
public class Father {
public static String staticFatherStr = "StaticFatherStr";
public String mNormalFatherStr = "NormalFatherStr";

static {
System.out.println("Father static code block, staticFatherStr = "
+ staticFatherStr);
}

{
System.out.println("Father Constructor code block,
mNormalFatherStr = " + mNormalFatherStr);
}

public Father(){
System.out.println("Father Constructor");
}
}

// 2. Son
public class Son extends Father{
public static String staticSonStr = "StaticSonStr";
public String mNormalSonStr = "NormalSonStr";

static {
System.out.println("Son static code block,
staticSonStr = " + staticSonStr);
}

{
System.out.println("Son Constructor code block,
mNormalSonStr = " + mNormalSonStr);
}

public Son(){
System.out.println("Son Constructor");
}

public static void main(String[] args) {
Son son = new Son();
System.out.println("***** Second Instance.#####");
Son second = new Son();
}
}

// 3. Result
Father static code block, staticFatherStr = StaticFatherStr
Son static code block, staticSonStr = StaticSonStr
Father Constructor code block, mNormalFatherStr = NormalFatherStr
Father Constructor
Son Constructor code block, mNormalSonStr = NormalSonStr
Son Constructor
***** Second Instance.#####
Father Constructor code block, mNormalFatherStr = NormalFatherStr
Father Constructor
Son Constructor code block, mNormalSonStr = NormalSonStr
Son Constructor

参考文档