Integer a = 1;
Integer b = 2;
System.out.println("before----a=" + a + ",b=" + b);
swap(a, b);
System.out.println("after----a=" + a + ",b=" + b);
交换a和b的值
输出结果为a=2,b=1
定义临时变量tmp,tmp=a;a=b;b=tmp
public class IntegerTest {
public static void main(String[] args) {
Integer a = 1;
Integer b = 2;
System.out.println("before----a=" + a + ",b=" + b);
swap(a, b);
System.out.println("after----a=" + a + ",b=" + b);
}
private static void swap(Integer a, Integer b) {
Integer tmp;
tmp = a;
a = b;
b = tmp;
}
}
输出结果:
并未交换成功?
原因在上一篇博客做了说明:
java是值传递还是引用传递?
从这个结果可以看出,swap方法传递的是值,因为交换a,b的值之后,原来的对象没有发生变化;
如果是引用传递,交换的是对象引用的地址,a,b就会发生变化,实际上却没有;
其实swap中传递的a,b只是传递的a,b值的副本,对副本进行操作不会影响原来的值。
了解了其中的原因,解题思路,和user.setName()
类似,Integer也是对象,当然也可以setInt(),使用反射
代码:
public class IntegerTest5 {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
Integer a = 1;
Integer b = 2;
System.out.println("before----a=" + a + ",b=" + b);
swap2(a, b);
System.out.println("after----a=" + a + ",b=" + b);
}
private static void swap(Integer a, Integer b) throws NoSuchFieldException, IllegalAccessException {
Field field = Integer.class.getDeclaredField("value");
field.setAccessible(true);
int aInt = field.getInt(a);
Integer tmp;
tmp = aInt;
field.setInt(a,field.getInt(b));
field.setInt(b,tmp);
}
}
为啥要用field.setAccessible(true);
?
因为Integer的实现方式 private final int value;
final类型不能被修改,·setAccessible(true);
之后可以跳过jdk的检查。
原理是
Field
继承了AccessibleObject
,setInt()
时会检查override
的值
而setAccessible(true)
可以修改override
的值,使其绕过这一段检查
执行结果:
a的值确实变成了2,但是b的值还是为2,并未变成1,继续往下看。
继续踩坑ing…?
为啥b的值没有改变,这里原因和Integer的自动装箱有关系,Integer a =1 , 1是int基本类型,但是这里用Integer接收,jdk会自动装箱。
Integer a =1
》Integer a = Integer.valueOf(1);
Integer 源码:
关键点就在IntegerCache
,当对象的值在-128~127之间的时候,对象的值实际上是存储在缓存中的,
why?为啥Integer要这么设计?
因为我们在使用Integer大部分情况下都是在-128~127之间,这么设计可以提高效率减少内存分配
这样产生的问题
Integer tmp;
tmp = aInt;
field.setInt(a,field.getInt(b));
field.setInt(b,tmp);
在最后一步设置b的值为tmp的时候,tmp的值实际上是a的缓存cache[k]
中的值,但是这个值在field.setInt(a,field.getInt(b));
的时候已经被替换为2,所以最后b设置的值为更新之后缓存cache[k]
中的2。
private static void swap1(Integer a, Integer b) throws NoSuchFieldException, IllegalAccessException {
Field field = Integer.class.getDeclaredField("value");
field.setAccessible(true);
int aInt = field.getInt(a)+128;
Integer tmp;
tmp = aInt;
field.setInt(a,field.getInt(b));
field.setInt(b,tmp-128);
}
private static void swap2(Integer a, Integer b) throws NoSuchFieldException, IllegalAccessException {
Field field = Integer.class.getDeclaredField("value");
field.setAccessible(true);
int aInt = field.getInt(a);
Integer tmp = new Integer(aInt);
field.setInt(a,field.getInt(b));
field.setInt(b,tmp);
}