類是如何被初始化的

2021-06-14 08:46:19 字數 3121 閱讀 9889

在寫dao工廠的時候遇到了這麼乙個問題:每次訪問資料的時候總是出錯,

提示下面的** daoconfig.load(int) 出錯!

public class daofactory  catch (ioexception e) 

} public static daofactory getinstance()

public t getdao(classklass) catch (exception e)

}}

開始真想不出這一行****出了問題,於是設定了乙個端點除錯一下,

發現daoconfig的值是null,這時才恍然大悟,於是將private static daofactory factory = new daofactory();

這段**移到private static properties daoconfig = new properties();下面,這樣問題就解決了!

那為什麼這樣改變一下**的位置就能解決這個問題呢?說到底還是類成員的初始化時機問題!

下面總結一下類成員的初始化過程,方便自己以後的複習!

在第一次遇上某類時,jvm就會載入該類的class檔案,如果該類有父類,則先載入其父類,並依此類推。

然後檢查class檔案的正確性,接著建立該類的class物件。隨著類的載入,進行類的靜態初始化,並且總是先執行父類的靜態初始化。

靜態初始化的順序是 

(1)為靜態變數分配記憶體空間

(2)將靜態變數預設初始化為0,false,null(其實是將分配了的記憶體的二進位制位置為0)

(3)按原始碼的排列順序進行初始化

例:

class p

}class test1

}

上面程式的輸出結果是-2和18

我們來梳理一遍就清楚為什麼是-2和18了

首先執行int m = p.p.b; 語句,jvm會載入p這個類,然後為p,a,b分配記憶體空間,執行預設初始化,此時

p的值為null,a和b的值為0,然後按順序為他們進行初始化,首先是new p(2); 呼叫p的建構函式,因為此時a為0

所以b的值是-2,接著為a賦值為20後結束。所以輸出m的值為-2。

輸出18的原因是類似的。

知道了這些,上面的daofactory為什麼出錯也是一清二楚了!

類的例項變數的初始化時機:

當第一次new 乙個物件時,先執行上面的靜態初始化,然後

(1)為成員變數分配記憶體空間

(2)將成員變數預設初始化為0,false,null(其實是將分配了的記憶體的二進位制位置為0)

(3)按原始碼的排列順序進行初始化

(4)執行建構函式

class test

int b = 5;

public string tostring()

public static void main(string args)

}

這段程式將輸出a = 100和 b = 10 

過程也就是上面所說的4步

阿里巴巴的一道筆試題

public class test 

static

public test(string str)

public static int print(string str)

/*** @param args

*/public static void main(string args)

}

第一步:載入類,為靜態變數分配記憶體空間,並對記憶體進行置0,此時k=0 , t1=null, t2=null ,i=0, n=0

第二步:根據靜態變數的宣告順序對其進行第一次初始化 首先 k=0

1:對t1進行初始化時,執行 new test("t1"),執行這條語句時,將會為j分配記憶體,並初始化 ,執行 print("j"),列印出1:j   i=0   n=0,此時k=1 i=1 n=1

然後繼續往下執行初始化塊中的語句 print("構造塊");  列印出2:構造塊   i=1   n=1 ,此時 k=2 i=2 n=2 ,接著,執行建構函式,列印出 3:t1   i=2   n=2,此時,k=3,i=3,n=3,至此 t1 初始化完成

2:對t2進行初始化,與t1的初始化類似執行 new test("t2"),執行這條語句時,將會為j分配記憶體(對於例項變數,每個例項都有乙份),並初始化 ,執行 print("j"),列印出4:j   i=3   n=3,此時k=4 i=4 n=4,然後繼續往下執行初始化塊中的語句 print("構造塊");  列印出5:構造塊   i=4   n=4 ,此時 k=5 i=5 n=5 ,接著,執行建構函式,列印出 6:t2   i=5   n=5, 至此 t2 初始化完成

3:初始化 i ,執行print("i") ,列印出7:i   i=6   n=6 , 此時 k=7 , i=7,n=7

4:初始化 n , n=99

第三步:執行 靜態**塊中的語句 print("靜態塊"); 列印出8:靜態塊   i=7   n=99 此時 k=8 , i=8,n=100

第四步:類變數的初始化完成後,執行 new test("init"),該例項有其自己的例項變數 j ,並為其分配記憶體,初始化,執行print("j") 列印出9:j   i=8   n=100 此時 k=9 i=9 n=100

接著執行初始化塊中的語句,print("構造塊") 列印出10:構造塊   i=9   n=101 此時 k=10 i=10 n=102

最後執行 建構函式 列印出 11:init   i=10   n=102  此時 k=11 i=11 n=103

至此 ,程式執行完畢。

最後的結果為:

1:j   i=0   n=0

2:構造塊   i=1   n=1

3:t1   i=2   n=2

4:j   i=3   n=3

5:構造塊   i=4   n=4

6:t2   i=5   n=5

7:i   i=6   n=6

8:靜態塊   i=7   n=99

9:j   i=8   n=100

10:構造塊   i=9   n=101

11:init   i=10   n=102

類什麼時候被初始化

1.建立乙個類的例項,也就是說new乙個物件的時候 2.訪問某個類或者介面的中的靜態變數,或者對靜態變數賦值的時候 3.呼叫類的靜態方法 4.反射 class.forname com.ysd.entity 5.初始化乙個類的子類 首先會先初始化它的父類 6.jvm啟動時標明的啟動類,就是檔名和類名相...

類的初始化

類的初始化通產有3種型別 使用初始化列表,在建構函式體中賦值,以及使用預設建構函式。先說前兩種 初始化列表與在建構函式體中賦值的區別在 呢?主要有兩點 第一,有的成員不能使用函式體中的 初始化。這其實就是初始化與賦值的區別 比如比如const 成員,引用型別,以及沒有定義預設建構函式的類,它們都必須...

類的初始化

類的初始化通產有3種型別 使用初始化列表,在建構函式體中賦值,以及使用預設建構函式。先說前兩種 初始化列表與在建構函式體中賦值的區別在 呢?主要有兩點 第一,有的成員不能使用函式體中的 初始化。這其實就是初始化與賦值的區別 比如比如const 成員,引用型別,以及沒有定義預設建構函式的類,它們都必須...