深入解析Integer類型:
補全Swap方法,使a b兩值交換。
public static void main(String[] args) {
// TODO Auto-generated method stub
Integer a=2;
Integer b=2;
swap(a,b);
System.out.println("a value is " +a);
System.out.println("b value is " +b);
}
private static void swap(Integer num1,Integer num2){
}
方法1(錯誤):
private static void swap(Integer num1,Integer num2){
Integer temp=num1;
num2=num1;
num1=temp;
}
由於Java傳輸數據採用值傳遞跟引用傳遞。
基本數據類型採用值傳遞,
Integer是包裝類,屬於基本數據類型int的封裝類型,其傳值採用值傳遞。
JDK1.5以後裝箱拆箱是其一個特性。
本來應該是 int a=1, 現在Integer a=1 可以直接賦值是因爲執行了裝箱操作:Integer.valueOf:[1]
調用swap的時候,只是傳給其a與b的副本,修改副本的value不影響a與b的值。
/**Integer與int的區別
區別1:創建Integer需要進行實例化。而int不需要實例化。因爲Integer是一個對象。
區別2:Integer默認是null。而int默認是0.
區別3:判斷Intege用equals,而判斷int用==。 原因的話挖坑,文章後期埋。
**/
方法2:
探索Integer怎麼賦值:
查看字節碼文件。
1. 進入JDK目錄。
2. Javap.exe -c +要解析的class路徑。
3. class字節碼文件解析--挖坑,以後再埋。
4. 調用Integer.valueOf把 1 壓入站點。
查看源碼文件:
Integer類中裏重要的是變量value。該值是final類型。
如果能夠使用set方式修改,那可以滿足要求。
使用set方式可以使用反射機制,用反射獲取到這個值。
private static void swap(Integer num1,Integer num2){
try {
Field field=Integer.class.getDeclaredField("value");
int temp=num1;
field.set(num1, num2);
field.set(num2, num1);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
但是這樣由於value是final修飾,會拋出異常。
在反射機制中,有訪問權限的設置。需要設置override值。
增加setAccessible並執行
private static void swap(Integer num1,Integer num2){
try {
Field field=Integer.class.getDeclaredField("value");
int temp=num1; //拆箱操作
field.setAccessible(true);
field.set(num1, num2);
field.set(num2, num1);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
結果是:
a value is 2
b value is 2
這是由於valueOf引起的。接下來查看valueOf的源碼:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
當i在IntegerCache的一定範圍內(low是-128,high是127),值從cache裏取。取值方法是i+ -(-128).
當i是1的時候,取的值應該是cache數組的129。
在做field.set(num1,num2)時候,其實就等於:cache[1+128]=2
在做field.set(num2,temp)時候,temp是int類型的1,而field.set參數是object對象,所以會進行一次自動的裝箱操作。等同於:
field.set(num2, Integer.valueOf(num1));
然後去cache中獲取值,得到的是cache[11+28]:2.
所以最終結果是a=2,b=2。
解決方案:
先埋文章開頭的坑:
當a>128的時候,用==就會出現問題,所以一般判斷Integer相等,用equals來進行判斷。
==比較的是內存地址是否一致。
當Integer在-128到127的時候,數據是從IntegerCache.cache[]中取。相當於是從一個對象中取,所以地址一致。
而當Integer取128的時候,重新分配了一個對象,地址發生變化,所以用==判斷爲false.
解決方案之解決方案:
主動刺破 temp的自動裝箱,讓其不從cache數組中取值。而從object對象中取。
private static void swap(Integer num1,Integer num2){
try {
Field field=Integer.class.getDeclaredField("value");
int temp=num1;
field.setAccessible(true);
field.set(num1, num2);
field.set(num2, new Integer(temp));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
當然,這樣會破壞Integer的封裝性。在實際項目中不建議這樣使用。