讀古今文學網 > 編寫高質量代碼:改善Java程序的151個建議 > 建議29:優先選擇基本類型 >

建議29:優先選擇基本類型

包裝類型是一個類,它提供了諸如構造方法、類型轉換、比較等非常實用的功能,而且在Java 5之後又實現了與基本類型之間的自動轉換,這使包裝類型如虎添翼,更是應用廣泛了,在開發中包裝類型已經隨處可見,但無論是從安全性、性能方面來說,還是從穩定性方面來說,基本類型都是首選方案。我們來看一段代碼:


public class Client{

public static void main(Stringargs){

Client cilent=new Client();

int i=140;

//分別傳遞int類型和Integer類型

cilent.f(i);

cilent.f(Integer.valueOf(i));

}

public void f(long a){

System.out.println("基本類型的方法被調用");

}

public void f(Long a){

System.out.println("包裝類型的方法被調用");

}

}


在上面的程序中首先聲明了一個int變量i,然後加寬轉變成long型,再調用f()方法,分別傳遞int和long的基本類型和包裝類型,諸位想想該程序是否能夠編譯?如果能編譯輸出結果又是什麼呢?

首先,這段程序絕對是能夠編譯的。不過,說不能編譯的同學還是很動了一番腦筋的,只是還欠缺點火候,你可能會猜測以下這些地方不能編譯:

f()方法重載有問題。定義的兩個f()方法實現了重載,一個形參是基本類型,一個形參是包裝類型,這類重載很正常。雖然基本類型和包裝類型有自動裝箱、自動拆箱的功能,但並不影響它們的重載,自動拆箱(裝箱)只有在賦值時才會發生,和重載沒有關係。

cilent. f(i)報錯。i是int類型,傳遞到fun(long l)是沒有任何問題的,編譯器會自動把i的類型加寬,並將其轉變為long型,這是基本類型的轉換規則,也沒有任何問題。

cilent. f(Integer.valueOf(i))報錯。代碼中沒有f(Integer i)方法,不可能接收一個Integer類型的參數,而且Integer和Long兩個包裝類型是兄弟關係,不是繼承關係,那就是說肯定編譯失敗了?不,編譯是成功的,稍後再解釋為什麼這裡編譯成功。

既然編譯通過了,我們來看一下輸出:


基本類型的方法被調用

基本類型的方法被調用


cilent. f(i)的輸出是正常的,我們已經解釋過了。那第二個輸出就讓人很困惑了,為什麼會調用f(long a)方法呢?這是因為自動裝箱有一個重要的原則:基本類型可以先加寬,再轉變成寬類型的包裝類型,但不能直接轉變成寬類型的包裝類型。這句話比較拗口,簡單地說就是,int可以加寬轉變成long,然後再轉變成Long對象,但不能直接轉變成包裝類型,注意這裡指的都是自動轉換,不是通過構造函數生成。為了解釋這個原則,我們再來看一個例子:


public class Client{

public static void main(Stringargs){

int i=100;

f(i);

}

public static void f(Long l){

}

}


這段程序編譯是通不過的,因為i是一個int類型,不能自動轉變為Long型。但是修改成以下代碼就可以編譯通過了:


public static void main(Stringargs){

int i=100;

long l=(long)i;

f(l);

}


這就是int先加寬轉變為long型,然後自動轉換成Long型。規則說明白了,我們繼續來看f(Integer.valueOf(i))是如何調用的,Integer.valueOf(i)返回的是一個Integer對象,這沒錯,但是Integer和int是可以互相轉換的。沒有f(Integer i)方法?沒關係,編譯器會嘗試轉換成int類型的實參調用,OK,這次成功了,與f(i)相同了,於是乎被加寬轉變成long型——結果也很明顯了。整個f(Integer.valueOf(i))的執行過程是這樣的:

i通過valueOf方法包裝成一個Integer對象。

由於沒有f(Integer i)方法,編譯器「聰明」地把Integer對像轉換成int。

int自動拓寬為long,編譯結束。

使用包裝類型確實有方便的地方,但是也會引起一些不必要的困惑,比如我們這個例子,如果f()的兩個重載方法使用的是基本類型,而且實參也是基本類型,就不會產生以上問題,而且程序的可讀性更強。自動裝箱(拆箱)雖然很方便,但引起的問題也非常嚴重——我們甚至都不知道執行的是哪個方法。

注意 重申,基本類型優先考慮。