當(dāng)new一個類對象時,如果該類還未被JVM所加載,則JVM首先加載該類,加載類流程中會有類的初始化操作,也就是類中static域的初始化,即調(diào)用<cinit>方法;在創(chuàng)建對象時,會進(jìn)行對象變量的初始化操作,即調(diào)用<init>方法;最后調(diào)用對象的構(gòu)造方法。
在類中static域初始化流程中,是按照前后順序來進(jìn)行的,也就是不管是static塊還是static變量,誰在前面誰就先初始化;在對象變量的初始化操作中,也是按照前后順序來進(jìn)行的,也就是不管是構(gòu)造代碼塊還是類屬性變量,誰在前面誰就先初始化。
類的靜態(tài)成員 --> 類的實(shí)例成員 --> 類的構(gòu)造方法
說到這里,有一個很好的問題。比如一個類中靜態(tài)變量是一個該類的實(shí)例,那么此時類的初始化順序是什么樣的呢?
public class Alibaba {
public static int k = 0;
public static Alibaba t1 = new Alibaba("t1");
public static Alibaba t2 = new Alibaba("t2");
public static int i = print("i");
public static int n = 99;
private int a = 0;
public int j = print("j");
{
print("構(gòu)造塊");
}
static {
print("靜態(tài)塊");
}
public Alibaba(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[]) {
Alibaba t = new Alibaba("init");
}
}
據(jù)說上述代碼是阿里14年校招題,輸出結(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
上面就是輸出結(jié)果,根據(jù)輸出結(jié)果,我們來分析下:
(1) 由于Alibaba類是JVM啟動類,所以首先被加載,也就是執(zhí)行加載、連接、初始化這些流程。
(2) 進(jìn)過加載和連接流程后,進(jìn)入初始化階段,該階段會對static域進(jìn)行初始化。
(3) 首先k被賦值為0,接下來是t1,由于這時Alibaba類已經(jīng)處于初始化階段了,static無需再次初始化,否則會導(dǎo)致static域多次初始化情況,所以暫時忽略static域初始化操作,對非static域進(jìn)行初始化操作,于是就有了開始的:
1:j i=0 n=0
2:構(gòu)造塊 i=1 n=1
3:t1 i=2 n=2
(4) 接著對t2賦值,過程與t1一樣:
4:j i=3 n=3
5:構(gòu)造塊 i=4 n=4
6:t2 i=5 n=5
(5) 然后對static變量i和n賦值,還有靜態(tài)塊初始化:
7:i i=6 n=6
8:靜態(tài)塊 i=7 n=99
(6) 此時已完成static域的初始化工作。執(zhí)行new Alibaba("init")
時,會觸發(fā)對象初始化操作,也就是以下輸出了:
9:j i=8 n=100
10:構(gòu)造塊 i=9 n=101
11:init i=10 n=102
參考:
1、http://liujiacai.net/blog/2014/07/12/order-of-initialization-in-java/