JAVA面試題解惑系列(一)——類的初始化順序
轉(zhuǎn)自:http://www.javaeye.com/topic/208187
大家在去參加面試的時(shí)候,經(jīng)常會(huì)遇到這樣的考題:給你兩個(gè)類的代碼,它們之間是繼承的關(guān)系,每個(gè)類里只有構(gòu)造器方法和一些變量,構(gòu)造器里可能還有一段代碼對(duì)變量值進(jìn)行了某種運(yùn)算,另外還有一些將變量值輸出到控制臺(tái)的代碼,然后讓我們判斷輸出的結(jié)果。這實(shí)際上是在考查我們對(duì)于繼承情況下類的初始化順序的了解。
我們大家都知道,對(duì)于靜態(tài)變量、靜態(tài)初始化塊、變量、初始化塊、構(gòu)造器,它們的初始化順序以此是(靜態(tài)變量、靜態(tài)初始化塊)>(變量、初始化塊)>構(gòu)造器。我們也可以通過下面的測(cè)試代碼來(lái)驗(yàn)證這一點(diǎn):
1
public class InitialOrderTest {
2
3
// 靜態(tài)變量
4
public static String staticField = "靜態(tài)變量";
5
// 變量
6
public String field = "變量";
7
8
// 靜態(tài)初始化塊
9
static {
10
System.out.println(staticField);
11
System.out.println("靜態(tài)初始化塊");
12
}
13
14
// 初始化塊
15
{
16
System.out.println(field);
17
System.out.println("初始化塊");
18
}
19
20
// 構(gòu)造器
21
public InitialOrderTest() {
22
System.out.println("構(gòu)造器");
23
}
24
25
public static void main(String[] args) {
26
new InitialOrderTest();
27
}
28
}
29

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

運(yùn)行以上代碼,我們會(huì)得到如下的輸出結(jié)果:
- 靜態(tài)變量
- 靜態(tài)初始化塊
- 變量
- 初始化塊
- 構(gòu)造器
這與上文中說(shuō)的完全符合。那么對(duì)于繼承情況下又會(huì)怎樣呢?我們?nèi)匀灰砸欢螠y(cè)試代碼來(lái)獲取最終結(jié)果:
1
class Parent {
2
// 靜態(tài)變量
3
public static String p_StaticField = "父類--靜態(tài)變量";
4
// 變量
5
public String p_Field = "父類--變量";
6
7
// 靜態(tài)初始化塊
8
static {
9
System.out.println(p_StaticField);
10
System.out.println("父類--靜態(tài)初始化塊");
11
}
12
13
// 初始化塊
14
{
15
System.out.println(p_Field);
16
System.out.println("父類--初始化塊");
17
}
18
19
// 構(gòu)造器
20
public Parent() {
21
System.out.println("父類--構(gòu)造器");
22
}
23
}
24
25
public class SubClass extends Parent {
26
// 靜態(tài)變量
27
public static String s_StaticField = "子類--靜態(tài)變量";
28
// 變量
29
public String s_Field = "子類--變量";
30
// 靜態(tài)初始化塊
31
static {
32
System.out.println(s_StaticField);
33
System.out.println("子類--靜態(tài)初始化塊");
34
}
35
// 初始化塊
36
{
37
System.out.println(s_Field);
38
System.out.println("子類--初始化塊");
39
}
40
41
// 構(gòu)造器
42
public SubClass() {
43
System.out.println("子類--構(gòu)造器");
44
}
45
46
// 程序入口
47
public static void main(String[] args) {
48
new SubClass();
49
}
50
}
51

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

運(yùn)行一下上面的代碼,結(jié)果馬上呈現(xiàn)在我們的眼前:
- 父類--靜態(tài)變量
- 父類--靜態(tài)初始化塊
- 子類--靜態(tài)變量
- 子類--靜態(tài)初始化塊
- 父類--變量
- 父類--初始化塊
- 父類--構(gòu)造器
- 子類--變量
- 子類--初始化塊
- 子類--構(gòu)造器
那么對(duì)于靜態(tài)變量和靜態(tài)初始化塊之間、變量和初始化塊之間的先后順序又是怎樣呢?是否靜態(tài)變量總是先于靜態(tài)初始化塊,變量總是先于初始化塊就被初始化了呢?實(shí)際上這取決于它們?cè)陬愔谐霈F(xiàn)的先后順序。我們以靜態(tài)變量和靜態(tài)初始化塊為例來(lái)進(jìn)行說(shuō)明。
同樣,我們還是寫一個(gè)類來(lái)進(jìn)行測(cè)試:
1
public class TestOrder {
2
// 靜態(tài)變量
3
public static TestA a = new TestA();
4
5
// 靜態(tài)初始化塊
6
static {
7
System.out.println("靜態(tài)初始化塊");
8
}
9
10
// 靜態(tài)變量
11
public static TestB b = new TestB();
12
13
public static void main(String[] args) {
14
new TestOrder();
15
}
16
}
17
18
class TestA {
19
public TestA() {
20
System.out.println("Test--A");
21
}
22
}
23
24
class TestB {
25
public TestB() {
26
System.out.println("Test--B");
27
}
28
}
29

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

運(yùn)行上面的代碼,會(huì)得到如下的結(jié)果:
- Test--A
- 靜態(tài)初始化塊
- Test--B
大家可以隨意改變變量a、變量b以及靜態(tài)初始化塊的前后位置,就會(huì)發(fā)現(xiàn)輸出結(jié)果隨著它們?cè)陬愔谐霈F(xiàn)的前后順序而改變,這就說(shuō)明靜態(tài)變量和靜態(tài)初始化塊是依照他們?cè)陬愔械亩x順序進(jìn)行初始化的。同樣,變量和初始化塊也遵循這個(gè)規(guī)律。
了解了繼承情況下類的初始化順序之后,如何判斷最終輸出結(jié)果就迎刃而解了。
posted on 2008-08-22 08:26 gdufo 閱讀(199) 評(píng)論(0) 編輯 收藏 所屬分類: JAVA 基礎(chǔ)