两个Integer的引用对象传给一个swap()在内部做交换引用后,两个引用的值是否发生变化

这是一道京东的面试题哦,考察的是值传递和引用传递的知识点。

先看一个值传递、引用传递的示例:

/**
 * 引用传递和值传递
 *
 * @author wanglingqiang
 * @date 2020/7/25 下午3:15
 **/
public class Test {

    public static void main(String[] args) {
        Test test = new Test();
        int a = 1;
        Obj obj = test.new Obj();
        obj.i = 2;
        System.out.println("main: " + a + ", " + obj.i);  // main: 1, 2
        test.ref(a, obj);
        System.out.println("main: " + a + ", " + obj.i);  //main: 1, 22
    }

    public void ref(int a, Obj b) {
        a = 11;
        b.i = 22;
        System.out.println("ref: " + a + ", " + b.i);  //ref: 11, 22
    }

    class Obj {
        int i;
    }
}

运行结果:

main: 1, 2
ref: 11, 22
main: 1, 22

int类型的值没被改变,对象的属性值被改变了。不理解的小伙伴可以看下图分析,理解的可以跳过看下一个String、Integer的示例。

画图分析引用传递:

在这里插入图片描述
栈里两个变量的引用都指向了堆里同一个的Obj对象,b.i赋值操作修改了堆的Obj属性,所以obj.i获取值时值发生了变化。

画图分析值传递:

在这里插入图片描述
ref()方法调用时,形参a会在栈里拷贝一份,并把局部变量a的值赋值给形参a,ref()方法内修改值时,实际修改的只是副本。


String、Integer包装类型是引用传递吗?

基本数据类型、引用数据类型,请参考:这里
Java中,String类型和八种基本数据类型的包装类型是例外,虽然它们是对象类型,但发生方法调用时其实是值传递。

/**
 * String、Integer包装类型的传值方式
 *
 * @author wanglingqiang
 * @date 2020/7/25 下午3:15
 **/
public class Test {

    public static void main(String[] args) {
        Test test = new Test();

        Integer a = 1;
        String b = "2";
        System.out.println("main: " + a + ", " + b);  // main: 1, 2
        test.ref2(a, b);
        System.out.println("main: " + a + ", " + b);  //main: 1, 2
    }

    public void ref2(Integer a, String b) {
        a = 11;
        b = "22";
        System.out.println("ref: " + a + ", " + b);  //ref: 11, 22
    }

}

运行结果:

main: 1, 2
ref: 11, 22
main: 1, 2

两个Integer值交换的示例:

京东的机试题:

进入正题,京东的机试题如下图:
在这里插入图片描述
题目要求,不能修改main()方法,只能在swap()方法内部编码。


常规思路,加一个中间变量temp:

在这里插入图片描述
结果未能如愿以偿,没有一个值被修改被替换。

画图分析常规做法的代码过程:
Integer temp = i;
在这里插入图片描述
i = j; j = temp;
在这里插入图片描述
如上图,常规方式交换,只是引用关系发生了变化,而是a、b的引用依然没变。堆对象里的值也没变化。


利用反射实现值交换:

曾经这道面试题也被我遇到过,我写下了用反射来交换值的过程,然后面试官问我,用反射会遇到什么问题,我一脸懵逼。现在回想起来,这个问题还挺深的,回答反射只算答对了一半。


用反射来交换值的代码如下:
在这里插入图片描述
但代码运行时会报错:

java.lang.IllegalAccessException: Class com.xxx.Test can not access a
member of class java.lang.Integer with modifiers “private final” at
sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102) at
java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
at java.lang.reflect.Field.set(Field.java:761) at com.crc.smartech.wisdomsite.biz.utils.Test.swap(Test.java:33) at
com.crc.smartech.wisdomsite.biz.utils.Test.main(Test.java:20)

因为value是private final修饰的。
在这里插入图片描述
报错的解决办法就是,授权可修改:
在这里插入图片描述
运行结果正常,但结果只交换了一个值。

画图分析一下原因:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
反射比较强势,直接改了堆内存里对象1的位置值为2,此时temp=1,再看看field.set(j, temp)方法的执行:
在这里插入图片描述
它接收的是一个Object对象类型,1传给value,被包装成了Integer类型的1,再通过valueOf()找到1的位置,发现值是2,所以field.set(j, temp)还是2。

原因找到了,那这个问题怎么解决呢?
在这里插入图片描述
new Integer(temp)的方式,生成一个新对象,此时运行结果交换成功。大功告成!


彩蛋,另一种解题方法:

听说有人用如下方法,面试官也给通过了。
在这里插入图片描述

惊不惊喜意不意外!!!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值