Java類初始化順序可能引起的bug
最近編程中遇到的問題, 類的成員初始化過程大家都很瞭解,都是基礎知識,但是有些地方很微妙,重新學習
下,來提高代碼質量。
先描述下遇到的場景:
子類構造器中調用super(),然後在父類構造器中調用子類有@overwrite的方法,子類在overwrite的方法中對自己成
員賦值,log輸出成功賦值,在子類new完,log打印發現部分成員變量值丟失了。
打印log發現list數據丟失了,int值還在,如下:
看了半天感覺還是很奇怪,有點不相信代碼的感覺,最後debug發現類成員的初始化影響了特殊情況數據的
丟失(重寫賦值)。
下面代碼研究下類成員的初始化,有些特殊而微妙的地方需要注意:
執行結果:
結論:
1繼承體系的所有靜態成員初始化(先父類,後子類)
2父類初始化完成(普通成員的初始化-->構造函數的調用)
3子類初始化(普通成員-->構造函數)
結合第一個有bug場景例子,可以很清晰的看出,父類構造完後會對子類(需要初始化)的成員進行初始化,這個
時候已經賦值的成員list會重新初始化,然後list數據丟失bug就出現了,解決這個問題只要賦值放在子類自己構造器裏
(成員初始化後),問題就解決了。
那麼問題來了,爲什麼同樣是成員變量的intValue沒有數據丟失呢? 繼續初始化分析debug,發現非靜態成員,
如果沒有顯式初始化賦值的話,相應類型的數據有默認的初始值(int類型爲0,引用類型爲null)。在類非靜態成員
初始化過程中,不會對這些值顯示賦值,所以上面例子中intValue在父類構造器中賦值後,數據能夠保留下來。so,例
子中的bug, 簡單的解決辦法還可以直接把定義地方的顯示賦值去掉就ok了。
後話:
1.java類中類是動態加載的,static成員可以在類未被實例化而使用,且對於靜態變量在內存中只有一個拷貝(節省存),JVM
只爲靜態分配一次內存,在加載類的過程中完成靜態變量的內存分配。在類初始化時,減少類初始化步驟,對代碼優化有一定提
高。
2.類成員的操作儘量要在自己類中調用操作,要儘量複合類設計原則:單一職責。不要產生過多複雜的引用關係,產生bug時
才能夠儘快分析出原因。
3.類非靜態成員定義時,如果業務邏輯允許,儘量不要對其定義時賦值,這樣,類在構造的時候就可以少很多初始化步驟,
加快類的初始化。