在寫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 成員,引用型別,以及沒有定義預設建構函式的類,它們都必須...