前言
今天在看Android ContentProvider實現的時候,突然想到了Java類在new的過程中,靜態域、靜態塊、非靜態域、非靜態塊、構造函數的執行順序問題。其實這是一個很經典的問題,非常考察對Java基礎知識的掌握程度。很多面試過程中相信也有這樣的問題,趁著周末有時間復習一下。
結論
這里先把整理好的結論拋給大家,然后我在寫個程序來驗證我們的結論。在Java類被new的過程中,執行順序如下:
- 實現自身的靜態屬性和靜態代碼塊。(根據代碼出現的順序決定誰先執行)
- 實現自身的非靜態屬性和非靜態代碼塊。
- 執行自身的構造函數。
在實現繼承的類被new的過程中,初始化執行順序如下:
- 實現父類的公共靜態屬性和靜態塊級代碼。
- 實現自身的靜態屬性和靜態塊級代碼。
- 實現父類的非靜態屬性和非靜態代碼塊。
- 執行父類的構造函數。
- 實現自身的非靜態屬性和非靜態代碼塊。
- 執行自身的構造函數。
這里需要簡單的介紹一下靜態代碼塊和非靜態代碼塊。
1. 靜態代碼塊:
static {
}
2. 非靜態代碼塊
{
}
靜態代碼塊和非靜態代碼塊的異同點如下:
- 相同點:都是JVM加載類時且在構造函數執行之前執行,在類中都可以定義多個,一般在代碼塊中對一些static變量進行賦值。
- 不同點:靜態代碼塊在非靜態代碼塊之前執行(靜態代碼塊 > 非靜態代碼塊)。靜態代碼塊只在第一次new時執行一次,之后不再執行。而非靜態代碼塊每new一次就執行一次。
驗證
對于結論的最好驗證就是寫出代碼來進行結果證明。首先,來看一下無繼承的類初始化時的執行順序,代碼如下:
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
|
public class InitOderTest { public static String STATIC_FIELD = "靜態屬性" ; // 靜態塊 static { System.out.println(STATIC_FIELD); System.out.println( "靜態代碼塊" ); } public String field = "非靜態屬性" ; // 非靜態塊 { System.out.println(field); System.out.println( "非靜態代碼塊" ); } public InitOderTest() { System.out.println( "無參構造函數" ); } public static void main(String[] args) { InitOderTest test = new InitOderTest(); } } |
執行結果:
- 靜態屬性
- 靜態代碼塊
- 非靜態屬性
- 非靜態代碼塊
- 無參構造函數
接下來,我們驗證一下,當Java類實現繼承后,執行順序是否和我們的結論吻合。測試代碼如下:
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
|
class ParentTest { public static String PARENT_STATIC_FIELD = "父類-靜態屬性" ; // 父類-靜態塊 static { System.out.println(PARENT_STATIC_FIELD); System.out.println( "父類-靜態代碼塊" ); } public static String parentField = "父類-非靜態屬性" ; // 父類-非靜態塊 { System.out.println(parentField); System.out.println( "父類-非靜態代碼塊" ); } public ParentTest() { System.out.println( "父類—無參構造函數" ); } } public class InitOderTest extends ParentTest { public static String STATIC_FIELD = "靜態屬性" ; // 靜態塊 static { System.out.println(STATIC_FIELD); System.out.println( "靜態代碼塊" ); } public String field = "非靜態屬性" ; // 非靜態塊 { System.out.println(field); System.out.println( "非靜態代碼塊" ); } public InitOderTest() { System.out.println( "無參構造函數" ); } public static void main(String[] args) { InitOderTest test = new InitOderTest(); } } |
執行結果如下:
- 父類-靜態屬性
- 父類-靜態代碼塊
- 靜態屬性
- 靜態代碼塊
- 父類-非靜態屬性
- 父類-非靜態代碼塊
- 父類—無參構造函數
- 非靜態屬性
- 非靜態代碼塊
- 無參構造函數