交換兩個變數的誤區(java)
阿新 • • 發佈:2019-01-05
在java中引數的傳遞有兩種方式,傳值和引用,實際上引用也是傳的值。當在一個方法中要交換兩個引數對應的值時,可能會有一系列問題。如下:
package com.xx;
import java.lang.reflect.Field;
public class Test01 {
public static void main(String[] args) {
Integer a = 1, b = 2;
swap(a, b);
System.out.println("a=" + a + "; b=" + b);
}
/**
* 交換變數a和b的值
*
* @param a
* @param b
*/
private static void swap(Integer a, Integer b) {
int tmp = a.intValue();
a = b;
b = tmp;
}
private static void swap1(Integer a, Integer b) {
try {
Field field = Integer.class.getDeclaredField("value");
field.setAccessible(true );//(1)
int tmp = a.intValue();//(2)
field.set(a, b.intValue());//(3)
System.out.println("tmp:" + tmp + "; valueOf:" + Integer.valueOf(tmp));//tmp:1; valueOf:2
System.out.println("a:" + a);//a:2
field.set(b, tmp);//(4-1)
//field.set(b, new Integer(tmp));//(4-2)
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
在swap(q,b)方法中直接交換後結果是沒有變化,因為此方法中的兩個變數都是區域性變數,方法執行完後變數失效,所有此種方式不行。
例項中的Integer是一個包裝類,而真正儲存值的是“private final int value;”,value是一個私有的變數,如果改變一個私有變數的值,可以使用反射。
(1):使用Field設定私有方法前,必須設定為可執行的
(2):此時tmp值為1,tmp指向的就是value的記憶體地址,即a的實際的值的記憶體地址
(3):set方法設定的是兩個Object物件,先將b.intValue()轉為包裝類(Integer.valueOf(xx))再設定,b的值在快取池中存在。此時a的值為2,即a中value指向的記憶體值也為2,也就是說tmp此時指向的記憶體地址的值為2
(4-1):此時如果直接將tmp的值設定到b中,那麼將tmp轉換為包裝類後的值為2(a.valueOf(tmp),快取中存在,並且上一步已將快取中的值修改)
(4-2):重新例項化一個物件,而不是從快取池中獲取
在Integer中,有一個快取池(-128 到 127),呼叫valueOf前會先判斷是否命中快取池