我们想要交换两个Integer的引用,题目代码如下:
public static void main(String[] args) throws Exception{
Integer a =1,b=2;
System.out.println("a="+a);
System.out.println("b="+b);
swager1(a,b);
System.out.println("after");
System.out.println("a="+a);
System.out.println("b="+b);
}
public static void swager1(Integer a,Integer b) throws Exception{
Integer tmp=a;
a=b;
b=tmp;
}
结果:
a=1
b=2
after
a=1
b=2
但是却并没有交换过来。我们知道Java有传值,传引用两种方式,这里一眼看去是传的引用,但是实际上是传的引用的副本,本质上仍然是值传递。既然传递的是引用的副本。引用操作,跟原来引用一毛钱关系都没有,所以两个Integer的值是不变的。
解决
辣么,怎么解决呢。首先要明白。为什么Integer a =1 ,为什么可以这么写,通过javap反编译查看字节码,返现Integer a =1,实际上是 Integer a = Integer.valueOf(1),也就是这里做了自动装箱。
查看Integer源代码
我们要改变Integer的值,只好是查看 Integer的源码:
/**
* The value of the {@code Integer}.
*
* @serial
*/
private final int value;
发现这个值是 final类型的,那么没办法了,只能通过反射来做修改,可以这样做:
public static void swager2(Integer a,Integer b) throws Exception{
Field field = Integer.class.getDeclaredField("value");
field.setAccessible(true);
int tmp = a.intValue();
field.set(a,b);
field.set(b,tmp);
}
但是,结果仍然不对:
a=1
b=2
after
a=2
b=2
field.set(a,b);把a的值设置成了b的值,没毛病。但是 在执行field.set(b,tmp)之前,Integer a 的值value已经修改为2了,所以tmp的值也变成2了;所以,上面的做法还是有问题,正确的做法如下:
public static void swager(Integer a,Integer b) throws Exception{
Field field = Integer.class.getDeclaredField("value");
field.setAccessible(true);
Integer tmp = new Integer(a.intValue());
field.set(a,b);
field.set(b,tmp);
}
新创建一个Integer对象,然后 field.set(b,tmp);就可以了。
总结
这个看似简单的面试题,考察了两个个知识点:
1.基础类型的自动装箱,拆箱
2.反射
还有一点需要注意,java虽然说有值传递,和引用传递,两种传值方式,但是广义上来讲都是值传递,引用只不过是引用的内存地址的副本。