java 中的 各種變量、代碼塊執行時機
前言:這屬于 java 的基礎知識,你可以不了解,也可以不拿它當一回事,代碼也一樣能敲的順暢;這是很久之前,我從 C++ 轉 java 剛入門那會的看法,那會我堅持自己的理念:重實踐,講運用,輕理論。當然,對同一樣事物,在不同階段也會有不一樣的看法,這理念在某個時段已經不適合我,早就被拋棄了。不扯淡了,直接進入主題。
java 中的變量大致分為 成員變量 和 局部變量 兩大類。
成員變量:
在類體里面定義的變量稱為成員變量;
如果該成員變量有 static 關鍵字修飾,則該成員變量稱為 靜態變量 或 類變量;
如果該成員變量沒有 static 關鍵字修飾,則該成員變量被稱為 非靜態變量 或 實例變量。
局部變量:
形參、方法內定義的變量、代碼塊中定義的變量,都屬于局部變量。
類變量 (靜態變量)
1. 可以向前引用
2. 變量屬于類本身
3. 類變量不依賴類的實例,類變量只在初始化時候在棧內存中被分配一次空間,無論類的實例被創建幾次,都不再為類變量分配空間
4. 通過類的任意一個實例來訪問類變量,底層都將將其轉為通過類本身來訪問類變量,它們的效果是一樣的
5. 一旦類變量的值被改變,通過類或類的任意一個實例來訪問類變量,得到的都將是被改變后的值
6. 將在類的初始化之前初始化
實例變量(非靜態變量)
1. 不能向前引用,如果向前引用,則稱為非法向前引用,這是不允許的
2. 變量屬于類的實例對象
3. 隨著類的實例被創建而分配內存空間
非靜態代碼塊
直接由 { } 包起來的代碼,稱為非靜態代碼塊
靜態代碼塊
直接由 static { } 包起來的代碼,稱為靜態代碼塊
類變量(靜態變量)、實例變量(非靜態變量)、靜態代碼塊、非靜態代碼塊 的初始化時機
由 static 關鍵字修飾的(如:類變量[靜態變量]、靜態代碼塊)將在類被初始化創建實例對象之前被初始化,而且是按順序從上到下依次被執行;
沒有 static 關鍵字修飾的(如:實例變量[非靜態變量]、非靜態代碼塊)初始化實際上是會被提取到類的構造器中被執行的,但是會比類構造器中的
代碼塊優先執行到,其也是按順序從上到下依次被執行。
- 以上是本人在翻完 PDF 后的個人筆記和理解以及見解,不見得百分百對,以下附上本人測試示例代碼,會更有說服性
示例代碼
1
2
/**
3
* -----------------------------------------
4
* @文件: Statical.java
5
* @作者: fancy
6
* @郵箱: fancydeepin@yeah.net
7
* @時間: 2012-7-9
8
* @描述: TEST
9
* -----------------------------------------
10
*/
11
public class Statical {
12
13
/**
14
* 靜態代碼塊
15
* 類變量(靜態變量)可以向前引用(即:先引用,再定義)
16
*/
17
static {
18
name = "fancydeepin"; // name 的定義在使用之后
19
System.out.println("---> 靜態代碼塊被執行 <---");
20
}
21
/**
22
* 類變量(靜態變量)在類的初始化之前初始化,無論類的實例將被創建多少個
23
* 類變量(靜態變量)都將只在初始化時候在棧內存上分配一次空間
24
* 凡 static 修飾的,都將按位置被順序執行,所以,
25
* name 的值最終輸出 fancy 而不是上面的 fancydeepin
26
*/
27
public static String name = "fancy"; //類變量(靜態變量)
28
private String mail = "myEmail"; //實例變量(非靜態變量),定義時指定初始值,會比在構造器賦予值更早執行
29
30
public Statical() {
31
mail = "fancydeepin@yeah.net";
32
System.out.println("---> 構造器代碼塊被執行 <---");
33
}
34
/**
35
* 非靜態代碼塊
36
* 實際上,非靜態代碼塊在類初始化創建實例時,將會被提取到類的構造器中,
37
* 但是,非靜態代碼塊會比構造器中的代碼塊優先被執行
38
* 所以,mail 最終輸出的是類構造器中給定的值,也就是 fancydeepin@yeah.net
39
* 而不是 1525336367@qq.com,更不是 myEmail
40
*/
41
{
42
mail = "1525336367@qq.com";
43
System.out.println("---> 非靜態代碼塊被執行 <---");
44
}
45
46
// getting and setting
47

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

測試類示例代碼
1
2
/**
3
* 類變量(靜態變量)在類被初始化創建實例之前被初始化
4
*/
5
System.out.println("-----------------> @1 <----------------");
6
System.out.println("name --->> " + Statical.name); // @1
7
System.out.println("-----------------> @1 <----------------");
8
/**
9
* 創建類的實例對象
10
*/
11
System.out.println("-----------------> @6 <----------------");
12
Statical statical = new Statical(); // @6
13
System.out.println("-----------------> @6 <----------------");
14
/**
15
* 通過實例來訪問類變量,底層將轉化成通過類本身來訪問類變量
16
*/
17
System.out.println("-----------------> @2 <----------------");
18
System.out.println("name --->> " + statical.name); // @2
19
System.out.println("-----------------> @2 <----------------");
20
/**
21
* 如果類變量的值被改變,再訪問類變量,將得到被改變后的值
22
*/
23
Statical.name = "fancydeepin";
24
25
System.out.println("-----------------> @3 <----------------");
26
System.out.println("name --->> " + statical.name); // @3
27
System.out.println("-----------------> @3 <----------------");
28
29
System.out.println("-----------------> @4 <----------------");
30
System.out.println("name --->> " + Statical.name); // @4
31
System.out.println("-----------------> @4 <----------------");
32
/**
33
* 非靜態代碼塊 和 構造器 被執行的時機
34
*/
35
System.out.println("-----------------> @5 <----------------");
36
System.out.println("mail --->> " + statical.getMail()); // @5
37
System.out.println("-----------------> @5 <----------------");
38

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

后臺輸出結果






















為了能更好的看出后臺的輸出是哪一行代碼執行的結果,我用了 @和數字來做了標記,希望大家不要看暈了哈 ^_^
最后針對輸出結果簡單說一下:
@1 說明,靜態(類變量、靜態代碼塊)屬于類本身,不依賴于類的實例
@6 說明,在創建類的實例對象的時候,非靜態代碼塊比構造器代碼塊更早的執行
@3 4 說明,當類變量的值改變后,再通過類或類的實例來訪問類變量,得到的將是被改變后的值
@5 說明,非靜態(實例變量、非靜態代碼塊)的地位是相等的,它們將按順序被執行,但會比構造器中的代碼塊更早的執行