分享一道java面试题 Integer值交换

文章目录

  • 1.题目
  • 2.思路
    • 2.1代码v1.0
    • 2.2代码v2.0
    • 2.3代码v3.0
      • 2.3.1解决思路一
      • 2.3.2解决思路二

1.题目

        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

2.思路

定义临时变量tmp,tmp=a;a=b;b=tmp

2.1代码v1.0

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面试题 Integer值交换_第1张图片
并未交换成功?
原因在上一篇博客做了说明:
java是值传递还是引用传递?

从这个结果可以看出,swap方法传递的是值,因为交换a,b的值之后,原来的对象没有发生变化;
如果是引用传递,交换的是对象引用的地址,a,b就会发生变化,实际上却没有;
其实swap中传递的a,b只是传递的a,b值的副本,对副本进行操作不会影响原来的值。

2.2代码v2.0

了解了其中的原因,解题思路,和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继承了AccessibleObjectsetInt()时会检查override的值
setAccessible(true)可以修改override的值,使其绕过这一段检查

分享一道java面试题 Integer值交换_第2张图片
分享一道java面试题 Integer值交换_第3张图片
分享一道java面试题 Integer值交换_第4张图片
执行结果:
在这里插入图片描述
a的值确实变成了2,但是b的值还是为2,并未变成1,继续往下看。

2.3代码v3.0

继续踩坑ing…?
为啥b的值没有改变,这里原因和Integer的自动装箱有关系,Integer a =1 , 1是int基本类型,但是这里用Integer接收,jdk会自动装箱。
Integer a =1Integer a = Integer.valueOf(1);
Integer 源码:
分享一道java面试题 Integer值交换_第5张图片
关键点就在IntegerCache,当对象的值在-128~127之间的时候,对象的值实际上是存储在缓存中的,

why?为啥Integer要这么设计?

因为我们在使用Integer大部分情况下都是在-128~127之间,这么设计可以提高效率减少内存分配
分享一道java面试题 Integer值交换_第6张图片
这样产生的问题

        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。

2.3.1解决思路一

    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);
   }

2.3.2解决思路二

    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);
   }

测试结果:
分享一道java面试题 Integer值交换_第7张图片

你可能感兴趣的:(分享一道java面试题 Integer值交换)