深度解析Integer

深入解析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的封裝性。在實際項目中不建議這樣使用。









發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章