讀古今文學網 > 編寫高質量代碼:改善Java程序的151個建議 > 建議40:匿名類的構造函數很特殊 >

建議40:匿名類的構造函數很特殊

在上一個建議中我們講到匿名類雖然沒有名字,但可以有一個初始化塊來充當構造函數,那這個構造函數是否就和普通的構造函數完全一樣呢?我們來看一個例子,設計一個計算器,進行加減乘除運算,代碼如下:


//定義一個枚舉,限定操作符

enum Ops{ADD, SUB}

class Calculator{

private int i, j,result;

//無參構造

public Calculator(){}

//有參構造

public Calculator(int_i, int_j){

i=_i;

j=_j;

}

//設置符號,是加法運算還是減法運算

protected void setOperator(Ops_op){

result=_op.equals(Ops.ADD)?i+j:i-j;

}

//取得運算結果

public int getResult(){

return result;

}

}


代碼的意圖是,通過構造函數輸入兩個int類型的數字,然後根據設置的操作符(加法還是減法)進行計算,編寫一個客戶端調用:


public static void main(Stringargs){

Calculator c1=new Calculator(1,2){

{

setOperator(Ops.ADD);

}

};

System.out.println(c1.getResult());

}


這段匿名類的代碼非常清晰:接收兩個參數1和2,然後設置一個操作符號,計算其值,結果是3,這毫無疑問,但是這中間隱藏著一個問題:帶有參數的匿名類聲明時到底是調用的哪一個構造函數呢?我們把這段程序模擬一下:


//加法計算

class Add extends Calculator{

{

setOperator(Ops.ADD);

}

//覆寫父類的構造方法

public Add(int_i, int_j){

}

}


匿名類和這個Add類是等價的嗎?可能有人會說:上面只是把匿名類增加了一個名字,其他的都沒有改動,那肯定是等價的啦!毫無疑問!那好,你再寫個客戶端調用Add類的方法看看。是不是輸出結果為0(為什麼是0?這很容易,有參構造沒有賦值)。這說明兩者不等價,不過,原因何在呢?

原來是因為匿名類的構造函數特殊處理機制,一般類(也就是具有顯式名字的類)的所有構造函數默認都是調用父類的無參構造的,而匿名類因為沒有名字,只能由構造代碼塊代替,也就無所謂的有參和無參構造函數了,它在初始化時直接調用了父類的同參數構造,然後再調用了自己的構造代碼塊,也就是說上面的匿名類與下面的代碼是等價的:


//加法計算

class Add extends Calculator{

{

setOperator(Ops.ADD);

}

//覆寫父類的構造方法

public Add(int_i, int_j){

super(_i,_j);

}

}


它首先會調用父類有兩個參數的構造函數,而不是無參構造,這是匿名類的構造函數與普通類的差別,但是這一點也確實鮮有人細細琢磨,因為它的處理機制符合習慣呀,我傳遞兩個參數,就是希望先調用父類有兩個參數的構造,然後再執行我自己的構造函數,而Java的處理機制也正是如此處理的!