讀古今文學網 > 編寫高質量代碼:改善Java程序的151個建議 > 建議28:優先使用整型池 >

建議28:優先使用整型池

上一建議我們解釋了包裝對象的比較問題,本建議將繼續深入討論相關問題,首先看如下代碼:


public static void main(Stringargs){

Scanner input=new Scanner(System.in);

while(input.hasNextInt()){

int ii=input.nextInt();

System.out.println("\n===="+ii+"的相等判斷======");

//兩個通過new產生的Integer對像

Integer i=new Integer(ii);

Integer j=new Integer(ii);

System.out.println("new產生的對象:"+(i==j));

//基本類型轉為包裝類型後比較

i=ii;

j=ii;

System.out.println("基本類型轉換的對象:"+(i==j));

//通過靜態方法生成一個實例

i=Integer.valueOf(ii);

j=Integer.valueOf(ii);

System.out.println("valueOf產生的對象:"+(i==j));

}

}


輸入多個數字,然後按照3種不同的方式產生Integer對象,判斷其是否相等,注意這裡使用了「==」,這說明判斷的不是同一個對象。我們輸入三個數字127、128、555,結果如下:


====127的相等判斷======

new產生的對象:false

基本類型轉換的對象:true

valueOf產生的對象:true

====128的相等判斷======

new產生的對象:false

基本類型轉換的對象:false

valueOf產生的對象:false

====555的相等判斷======

new產生的對象:false

基本類型轉換的對象:false

valueOf產生的對象:false


很不可思議呀,數字127的比較結果竟然與其他兩個數字不同,它的裝箱動作所產生的對象竟然是同一個對象,valueOf產生的也是同一個對象,但是大於127的數字128和555在比較過程中所產生的卻不是同一個對象,這是為什麼?我們一個一個來解釋。

(1)new產生的Integer對像

new聲明的就是要生成一個新的對象,沒二話,這是兩個對象,地址肯定不等,比較結果為false。

(2)裝箱生成的對象

對於這一點,首先要說明的是裝箱動作是通過valueOf方法實現的,也就是說後兩個算法是相同的,那結果肯定也是一樣的,現在的問題是:valueOf是如何生成對象的呢?我們來閱讀一下Integer.valueOf的實現代碼:


public static Integer valueOf(int i){

final int offset=128;

if(i>=-128&&i<=127){//must cache

return IntegerCache.cache[i+offset];

}

return new Integer(i);

}


這段代碼的意思已經很明瞭了,如果是-128到127之間的int類型轉換為Integer對象,則直接從cache數組中獲得,那cache數組裡是什麼東西,代碼如下:


static final Integer cache=new Integer[-(-128)+127+1];

static{

for(int i=0;i<cache.length;i++)

cache[i]=new Integer(i-128);

}


cache是IntegerCache內部類的一個靜態數組,容納的是-128到127之間的Integer對象。通過valueOf產生包裝對像時,如果int參數在-128和127之間,則直接從整型池中獲得對象,不在該範圍的int類型則通過new生成包裝對象。

明白了這一點,要理解上面的輸出結果就迎刃而解了,127的包裝對象是直接從整型池中獲得的,不管你輸入多少次127這個數字,獲得的對象都是同一個,那地址當然都是相等的。而128、555超出了整型池範圍,是通過new產生一個新的對象,地址不同,當然也就不相等了。

以上的解釋也是整型池的原理,整型池的存在不僅僅提高了系統性能,同時也節約了內存空間,這也是我們使用整型池的原因,也就是在聲明包裝對象的時候使用valueOf生成,而不是通過構造函數來生成的原因。順便提醒大家,在判斷對象是否相等的時候,最好是用equals方法,避免用「==」產生非預期結果。

注意 通過包裝類的valueOf生成包裝實例可以顯著提高空間和時間性能。