讀古今文學網 > 編寫高質量代碼:改善Java程序的151個建議 > 建議37:構造代碼塊會想你所想 >

建議37:構造代碼塊會想你所想

上一個建議中我們提議使用構造代碼塊來簡化代碼,並且也瞭解到編譯器會自動把構造代碼塊插入到各個構造函數中,那我們接下來看看編譯器是不是足夠聰明,能夠為我們解決真實的開發問題。有這樣一個案例:統計一個類的實例數量。可能你要說了,這很簡單,在每個構造函數中加入一個對像計數器不就解決問題了嗎?或者使用我們上一個建議介紹的,使用構造代碼塊也可以。確實如此,我們來看如下代碼是否可行:


public class Client{

public static void main(Stringargs){

new Base();

new Base("");

new Base(0);

System.out.println("實例對像數量:"+Base.getNumOfObjects());

}

}

class Base{

//對像計數器

private static int numOfObjects=0;

{

//構造代碼塊,計算產生對像數量

numOfObjects++;

}

public Base(){

}

//有參構造調用無參構造

public Base(String_str){

this();

}

//有參構造不調用其他構造

public Base(int_i){

}

//返回在一個JVM中,創建了多少個實例對像

public static int getNumOfObjects(){

return numOfObjects;

}

}


這段代碼是可行的嗎?能計算出實例對象的數量嗎?哎,好像不對呀,如果編譯器把構造代碼塊插入到各個構造函數中,那帶有String形參的構造函數可就有問題,它會調用無參構造,那通過它生成Base對像時就會執行兩次構造代碼塊:一次是由無參構造函數調用構造代碼塊,一次是執行自身的構造代碼塊,這樣的話計算可就不準確了,main函數實際在內存中產生了3個對象,但結果卻會是4。不過真是這樣的嗎?Are you sure?我們運行一下看看結果:

實例對像數量:3

非常遺憾,你錯了,實例對象的數量還是3,程序沒有任何問題。奇怪嗎?不奇怪,上一個建議是說編譯器會把構造代碼塊插入到每一個構造函數中,但是有一個例外的情況沒有說明:如果遇到this關鍵字(也就是構造函數調用自身其他的構造函數時)則不插入構造代碼塊,對於我們的例子來說,編譯器在編譯時發現String形參的構造函數調用了無參構造,於是放棄插入構造代碼塊,所以只執行了一次構造代碼塊——結果就是如此。

那Java編譯器為什麼會這麼聰明呢?這還要從構造代碼塊的誕生說起,構造代碼塊是為了提取構造函數的共同量,減少各個構造函數的代碼而產生的,因此,Java就很聰明地認為把代碼塊插入到沒有this方法的構造函數中即可,而調用其他構造函數的則不插入,確保每個構造函數只執行一次構造代碼塊。

還有一點需要說明,讀者千萬不要以為this是特殊情況,那super也會類似處理了。其實不會,在構造代碼塊的處理上,super方法沒有任何特殊的地方,編譯器只是把構造代碼塊插入到super方法之後執行而已,僅此不同。

注意 放心地使用構造代碼塊吧,Java已經想你所想了。