在上一個建議中我們講到匿名類雖然沒有名字,但可以有一個初始化塊來充當構造函數,那這個構造函數是否就和普通的構造函數完全一樣呢?我們來看一個例子,設計一個計算器,進行加減乘除運算,代碼如下:
//定義一個枚舉,限定操作符
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的處理機制也正是如此處理的!