先看一段代碼:
public class Text {
public static int k = 0;
public static Text t1 = new Text("t1");
public static Text t2 = new Text("t2");
public static int i = print("i");
public static int n = 99;
public int j = print("j");
{
print("構(gòu)造塊");
}
static {
print("靜態(tài)塊");
}
public Text(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[]) {
Text t = new Text("init");
}
}
輸出結(jié)果為:
1:j i=0 n=0
2:構(gòu)造塊 i=1 n=1
3:t1 i=2 n=2
4:j i=3 n=3
5:構(gòu)造塊 i=4 n=4
6:t2 i=5 n=5
7:i i=6 n=6
8:靜態(tài)塊 i=7 n=99
9:j i=8 n=100
10:構(gòu)造塊 i=9 n=101
11:init i=10 n=102
加載過程分析
執(zhí)行main時挣饥,先加載所在類,聲明靜態(tài)變量排宰,并初始化靜態(tài)變量執(zhí)行靜態(tài)代碼塊(按順序執(zhí)行)
初始化到t1時褐鸥,暫停類加載线脚,先實例化,此時k=0叫榕,而i浑侥,n都未初始化,系統(tǒng)默認值為0
初始化j時晰绎,k自增為1寓落,i,n為0荞下,輸出“1:j i=0 n=0”伶选,n,i自增為1
執(zhí)行代碼塊,輸出“2:構(gòu)造塊 i=1 n=1”尖昏,n,i自增為2
執(zhí)行構(gòu)造函數(shù)仰税,輸出“3:t1 i=2 n=2”,n,i自增為3
初始化到t2時抽诉,暫停類加載陨簇,先實例化,此時k=3掸鹅,i塞帐,n都還未初始化拦赠,但已自增為3
初始化j時,k自增為4葵姥,i荷鼠,n未初始化為3,輸出“4:j i=3 n=3”榔幸,n,i自增為4
執(zhí)行代碼塊允乐,輸出“5:構(gòu)造塊 i=4 n=4”,n,i自增為5
執(zhí)行構(gòu)造函數(shù)削咆,輸出“6:t2 i=5 n=5”牍疏,n,i自增為6
初始化i,輸出“7:i i=6 n=6”拨齐,n,i自增為7鳞陨,返回自增后的i賦值給i
初始化n,賦值99
執(zhí)行靜態(tài)塊瞻惋,輸出“8:靜態(tài)塊 i=7 n=99”厦滤,i自增為8,n自增為100
完成類加載歼狼,執(zhí)行Text t = new Text("init");
初始化成員變量j掏导,輸出9:j i=8 n=100
調(diào)用構(gòu)造塊和構(gòu)造方法,輸出 10:構(gòu)造塊 i=9 n=101
11:init i=10 n=102
涉及要點
1.類加載過程:
加載某類前先加載其父類
加載某類時羽峰,先聲明靜態(tài)成員變量趟咆,初始化為默認值,再初始化靜態(tài)成員變量執(zhí)行靜態(tài)代碼塊
初始化靜態(tài)成員變量執(zhí)行靜態(tài)代碼塊時梅屉,是按順序執(zhí)行(初始化靜態(tài)成員變量的本質(zhì)就是靜態(tài)代碼塊)
2.實例化過程:
對某類實例化前值纱,先對其父類進行實例化
實例化某類時,先聲明成員變量履植,初始化為默認值计雌,再初始化成員變量執(zhí)行代碼塊
初始化成員變量執(zhí)行代碼塊時,是按順序執(zhí)行
3.在某類加載過程中調(diào)用了本類實例化過程(如new了本類對象)玫霎,則會暫停類加載過程先執(zhí)行實例化過程凿滤,執(zhí)行完畢再回到類加載過程
類的主動使用與被動使用
主動使用例子:
1):最為常用的new一個類的實例對象
2):直接調(diào)用類的靜態(tài)方法。
3):操作該類或接口中聲明的非編譯期常量靜態(tài)字段
4):反射調(diào)用一個類的方法庶近。
5):初始化一個類的子類的時候翁脆,父類也相當于被程序主動調(diào)用了
(如果調(diào)用子類的靜態(tài)變量是從父類繼承過來并沒有復寫的,那么也就相當于只用到了父類的東東鼻种,和子類無關(guān)反番,
所以這個時候子類不需要進行類初始化)。
6):直接運行一個main函數(shù)入口的類。
所有的JVM實現(xiàn)罢缸,在首次主動使用某類的時候才會加載該類篙贸。
被動使用例子:
1):子類調(diào)用父類的靜態(tài)變量,子類不會被初始化枫疆。只有父類被初始化爵川。對于靜態(tài)字段,只有直接定義這個字段的類才會被初始化.
2):通過數(shù)組定義來引用類息楔,不會觸發(fā)類的初始化寝贡,如SubClass[] sca = new SubClass[10];
3):訪問類的編譯期常量,不會初始化類