面试题:说出你的答案:
public static void main(String[] args) {
Integer i = 1;
Integer j = 2;
swap(i, j);
System.out.println("i=" + i + "----------j=" + j);
}
private static void swap(Integer m, Integer n) {
Integer temp = m;
m = n;
n = temp;
}
------------------------------------------------------------------------------分割线----------------------------------------------------------------------------------
答案是 // i=1----------j=2
why没变?
因为调用方法,只是将 i 和 j 地址赋给了 m 和 n
swap方法内,又将 n 赋给了 m, 将 m 赋给了 n,这一切与 i 、 j 无关。
比如:下面list的例子
不改变参数的内存指向,直接操作list内的值,才能改变list。而new一个新list,将参数内存指向改了,与原list已经没有关系了。
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("123");
change(list);
swap(list);
System.out.println(list); // [123, 456]
}
// 会增加
private static void change(List<String> list) {
list.add("456");
}
// 不会影响原list
private static void swap(List<String> list) {
list = new ArrayList<>();
list.clear();
list.add("789");
}
------------------------------------------------------------------------------分割线----------------------------------------------------------------------------------
那么,问题来了,面试题中,怎么让 i 和 j 的值进行交换?
肯定不能如题目中直接赋值,赋值将内存指向改变了,失去了和 i 和 j 的关联,交换从何谈起。
应该操作Integer内的值。
Integer的值存在成员变量value中,类似于list中的元素"123",但value是private final的,怎么改?只能用暴力反射!
private static void swap(Integer i, Integer j) {
try {
int temp = i;
Field field = Integer.class.getDeclaredField("value");
field.setAccessible(true);
field.set(i, j);
field.set(j, temp);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
bug结果是i=2----------j=2,why?
这里要了解Integer对-128-127的缓存IntegerCache:
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
...
}
cache[]数组将-128-127之间的整数,缓存了起来。
field.set(i, j),将 i 这个Integer变成了2,缓存内该索引下的Integer也变成了2
这时候field.set(j, temp);第二个参数要的是Object,所以这里存在一个对temp的自动装箱,查看自动装箱valueOf函数:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
IntegerCache.cache[i + (-IntegerCache.low)],找cache[129]下的Integer,就是原来的 i ,已经变成了2(缓存内现在已经没有1这个Integer了,而是有两个2)。所以结果 j 也是2。
------------------------------------------------------------------------------分割线----------------------------------------------------------------------------------
那么,问题怎么解决?只要j不从缓存里取,new一个新的Integer即可:
private static void swap(Integer i, Integer j) {
try {
Integer temp = new Integer(i);
Field field = Integer.class.getDeclaredField("value");
field.setAccessible(true);
field.set(i, j);
field.set(j, temp);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}