標籤:
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.類非靜態成員定義時,如果商務邏輯允許,盡量不要對其定義時賦值,這樣,類在構造的時候就可以少很多初始化步驟,
加快類的初始化。
從Java類初始化,來看代碼最佳化