一道java JDK面试题引发的思考

这道面试题所设计的知识点:

  • 传值和传引用的区别
  • 装箱和拆箱
  • java的内存模型
  • 反射

面试题需求:

主方法定义两个Integer变量,并赋值,然后通过一个swap()方法交换变量的值,请写出swap()中的实现

public static void main(String[] args) {
    Integer a = 1;
    Integer b = 2;
    System.out.println("before swap :a = " + a + ",b = " + b);
    swap(a, b);
    System.out.println("after swap :a = " + a + ",b = " + b);
}

当看到这个面试题的时候第一感觉就是在swap()方法中定义一个变量,例如:

private static void swap(Integer num1, Integer num2) {

    Integer tmp = num1;
    num1 = num2;
    num2 = tmp;

}

但是运行结果不尽人意:

before swap :a = 1,b = 2
after swap :a = 1,b = 2

这就牵扯到传值的方式,传值的方式有两种,按值传递,引用传递,那上面这个swap()方法是按那种方式传值的呢?

这里是按值传递;

值传递:
在方法被调用时,实参通过形参把它的内容副本传入方法内部,此时形参接收到的内容是实参值的一个拷贝,因此在方法内对形参的任何操作,都仅仅是对这个副本的操作,不影响原始值的内容。
sd

到了swap()方法,还没有进行交换时:

经过了swap()方法之后,num1和num2进行了交换:

可以看到其实并没有影响到a和b的值;

这里还有一个问题就是Integer a = 1; 是自动装箱,怎么实现自动装箱的? 大家都用过Integer.valueOf()

Integer a = Integer.valueOf(1);所以说Integer a = 1就是一个装箱的操作;

那valueOf()这个方法中又做了什么事呢?

    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

有两个变量 low ,high ,low=-128,high=127;也就是说在这两个值之间的值都会从缓存里去取;不在这两个值之间的才会去new 一个Integer对象;

上面我们使用一个中间变量是不能实现的交换的,那我们使用发射试试;

 private static void swap(Integer num1, Integer num2) {

        try {
            int tmp = num1.intValue();
            Field field = Integer.class.getDeclaredField("value");
            field.setAccessible(true); // private final int value; 私有属性,使用暴力反射
            field.set(num1, num2);
            field.set(num2, tmp);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

运行结果:

before swap :a = 1,b = 2
after swap :a = 2,b = 2

发现还是不行;只是a成功交换,但是b没有交换;这里因为num1的下标对应的值被改成了2,所以当给num2设置值的时候,其实设置的还是2,这里可以打个断点到valueOf()这个方法中看看;这里就不阐述过多;

为了引出正确的解决方法我们引入一个简单的知识点:上面我们也看了在[-128~127]之间是从缓存中取的;

那下面这两段代码是打印true还是false呢?

public static void main(String[] args) {
    Integer a = 1;
    Integer b = 1;

    System.out.println(a==b);
}   
public static void main(String[] args) {
    Integer a = 128;
    Integer b = 128;
	System.out.println(a==b);
} 

1之间的比较是true ,128之间的比较是false,1没有超出这个缓存的范围,但是128已经超出了缓存的范围,就要就new Integer();

所以这个面试题正确的解决方法是:

private static void swap(Integer num1, Integer num2) {
        try {
            int tmp = num1.intValue();
            Field field = Integer.class.getDeclaredField("value");
            field.setAccessible(true); // private final int value; 私有属性,使用暴力反射
            field.set(num1, num2);
            field.set(num2,new Integer(tmp));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

打印结果:

before swap :a = 1,b = 2
after swap :a = 2,b = 1

成功的进行了交换;对num1–>Integer tmp = new Integer(num1);不要让它取缓存里的值;缓存中下标对应的值改变也对num2的赋值没有影响;因为num1是重新new 的对象;

知道了上面的原理,我们把a和b的值分别变成777 和999 那会不会成功交换呢?自己可以下去试一试;

还有没有其他的解决方式呢?当然是有的;我们可以把

field.set(num1, num2);
field.set(num2, tmp);
//改成
field.setInt(num1,num2);
field.setInt(num2,tmp);

field.setInt(num1,num2);中num2是需要int类型;这就不是装箱了而是拆箱

至此 这道面试题所涉及的东西就说完了;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值