上一建議我們解釋了包裝對象的比較問題,本建議將繼續深入討論相關問題,首先看如下代碼:
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生成包裝實例可以顯著提高空間和時間性能。