讀古今文學網 > 編寫高質量代碼:改善Java程序的151個建議 > 建議35:避免在構造函數中初始化其他類 >

建議35:避免在構造函數中初始化其他類

構造函數是一個類初始化必須執行的代碼,它決定著類的初始化效率,如果構造函數比較複雜,而且還關聯了其他類,則可能產生意想不到的問題,我們來看如下代碼:


public class Client{

public static void main(Stringargs){

Son s=new Son();

s.doSomething();

}

}

//父類

class Father{

Father(){

new Other();

}

}//子類

class Son extends Father{

public void doSomething(){

System.out.println("Hi, show me something");

}

}

//相關類

class Other{

public Other(){

new Son();

}

}


這段代碼並不複雜,只是在構造函數中初始化了其他類,想想看這段代碼的運行結果是什麼?是打印"Hi, show me something"嗎?

答案是這段代碼不能運行,報StackOverflowError異常,棧(Stack)內存溢出。這是因為聲明s變量時,調用了Son的無參構造函數,JVM又默認調用了父類Father的無參構造函數,接著Father類又初始化了Other類,而Other類又調用了Son類,於是一個死循環就誕生了,直到棧內存被消耗完畢為止。

可能有讀者會覺得這樣的場景不可能在開發中出現,那我們來思考這樣的場景:Father是由框架提供的,Son類是我們自己編寫的擴展代碼,而Other類則是框架要求的攔截類(Interceptor類或者Handle類或者Hook方法),再來看看該問題,這種場景不可能出現嗎?

那有讀者可能要說了,這種問題只要系統一運行就會發現,不可能對項目產生影響。

那是因為我們在這裡展示的代碼比較簡單,很容易一眼洞穿,一個項目中的構造函數可不止一兩個,類之間的關係也不會這麼簡單的,要想瞥一眼就能明白是否有缺陷這對所有人員來說都是不可能完成的任務,解決此類問題的最好辦法就是:不要在構造函數中聲明初始化其他類,養成良好的習慣。