前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >两个Integer的引用对象传递给一个swap方法的内部进行交换,返回后,两个引用的值是否会发生变化

两个Integer的引用对象传递给一个swap方法的内部进行交换,返回后,两个引用的值是否会发生变化

作者头像
须臾之余
发布2019-08-20 10:58:34
3K1
发布2019-08-20 10:58:34
举报
文章被收录于专栏:须臾之余须臾之余须臾之余

示例一:

/**
 * 大厂面试题(微博、百度、腾讯):
 *      两个Integer的引用对象传递给一个swap方法的内部进行交换,返回后,两个引用的值是否会发生变化
 */
public class Test001 {
    public static void main(String[] args) {
        Integer a=1,b=2;
        //a=Integer@533=1,b=Integer@534=2
        System.out.println("before:a="+a+",b="+b);
        swap(a,b);
        //a=Integer@533=1,b=Integer@534=2
        System.out.println("after:a="+a+",b="+b);
    }
    private static void swap(Integer i1, Integer i2) {
        //tmp=i1=Integer@533---1
        Integer tmp=i1;
        //i1=i2=Integer534@--2
        i1=i2;
        //i2=tmp=i1=Integer@533----1
        i2=tmp;
    }

输出结果:

数组元素作为函数的实参时,用法跟普通变量作参数相同,将数组元素的值传递给形参时进行函数体调用,函数调用完返回后,数组元素的值不变。这种传递方式是”值传递“方式,即只能从实参传递给形参,而不能从形参传递给实参

我们通过Java反编译工具查看,底层通过Integer.valueOf()来转换

我们通过源码来看看valueOf()方法实现原理

public static Integer valueOf(int i) {
    //如果是在Integer缓存中-128到127之间则去缓存中取值
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    //否则直接开辟一个新的内存空间
    return new Integer(i);
}
private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];//缓存数组

.....
}

我们Integer a=1,b=2在Integer缓存范围之内,所以走 return IntegerCache.cache[i + (-IntegerCache.low)];去缓存数组中拿值

线程对变量的所有操作(读取、赋值)都必须在工作内存中进行,而不能直接读写主内存中的变量。在swap方法内部交换引用,只会交换线程的工作内存中持有的方法参数, 而工作内存中的方法参数是主内存中变量的副本,因此执行这样的swap方法不会改变主内存中变量的指向  

案例二:

public class Test002 {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        Integer a=1,b=2;
        //a=Integer@534=1,b=Integer@535=2
        System.out.println("before:a="+a+",b="+b);
        swap(a,b);
        //a=Integer@534=2,b=Integer@535=2
        System.out.println("after:a="+a+",b="+b);
    }
    private static void swap(Integer i1, Integer i2) throws NoSuchFieldException, IllegalAccessException {
        //反射获取成员变量
        Field value = Integer.class.getDeclaredField("value");
        value.setAccessible(true);
        //tmp=1
        int tmp=i1.intValue();
        //i1=Integer@534=2
        value.set(i1,i2.intValue());
        //i2=Integer@535=tmp=i1.intValue()=2
        value.set(i2,tmp);
    }

输出结果

使用反射机制,传递的是数组元素对应的地址,这样形参数组和实参数组共占用一段内存单元,当形参值发生变化时,实参值也发生变化。

查看反编译结果

private final int value;

交换的是引用地址,修改成员变量final value的值,可用通过反射机制修改。

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

还是会去Integer缓存数组中找到这个值2,并设置给 i1,因为tmp=i1.intValue(),栈中的tmp的地址会指向Integer在堆中数组对应值为i1的地址,所以

经过 value.set(i1, Integer.valueOf(i2.intValue()));之后,tmp就=2,最后 value.set(i2, Integer.valueOf(tmp));将2赋值给 i2.

案例三:

public class Test003 {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        Integer a=1,b=2;
        //a=Integer@534=1,b=Integer@535=2
        System.out.println("before:a="+a+",b="+b);
        swap(a,b);
        //a=Integer@534=2,b=Integer@535=1
        System.out.println("after:a="+a+",b="+b);
    }
    private static void swap(Integer i1, Integer i2) throws NoSuchFieldException, IllegalAccessException {
        //反射获取成员变量
        Field value = Integer.class.getDeclaredField("value");
        value.setAccessible(true);
        //重新开辟一个内存空间
        //tmp=Integer@545=1
        Integer tmp=new Integer(i1.intValue());
        //i1=Integer@534=2
        value.set(i1,i2.intValue());
        //i2=Integer@535=tmp=new Integer(i1.intValue())=1
        value.set(i2,tmp);

    }
}

输出结果为:

这里总总结前面的经验,new Integer开辟新的内存空间,不会走缓存了

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档