JAVA面试题之值传递与引用传递

问题引出

两个Integer的引用对象传给一个swap方法在方法内部进行交换(返回后,两个引用的值是否会发生变化),swap交换函数如何编写使得两个值交换?

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

问题解决

首先,答案是不是简单地交换两个值?
答:错误!swap传递的基本类型数据,副本式的地址,不会影响到原始值

 public static void swap(Integer i1,Integer i2){
        //TODO
        Integer tmp = i1;
        i1 = i2;
        i2 = tmp;
    }

所以,我们看一下,Integer的值存在哪里了?

 public final class Integer extends Number implements Comparable<Integer> {
    private final int value;
    
    public Integer(int value) {
        this.value = value;
    }
   }

打开源码发现,存在私有的final常量里!所以,想要改变Integer的值,只能通过反射改变其内存地址。于是

public static void swap(Integer i1,Integer i2) throws NoSuchFieldException, IllegalAccessException{
        //TODO
        Field field = Integer.class.getDeclaredField("value");
        //暴力访问私有成员变量
        field.setAccessible(true);
        int tmp = i1.intValue();
        field.set(i1,i2.intValue());
        field.set(i2,tmp);
    }

我们运行一下:

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

发现b还是没有改变!用javap看一下字节码被编译的过程

命令:javap -v  ‘字节码文件名称’

在这里插入图片描述
我们看main方法jvm执行指令,发现是Integer.valueOf(i)进行赋值:
在这里插入图片描述
相当于我们在Integer a = 1的时候,Integer a = Integer.valueOf(1);
所以我们看一下Integer的valueOf

    public static Integer valueOf(String s, int radix) throws NumberFormatException {
        return Integer.valueOf(parseInt(s,radix));
    }

点进去,看一下实现过程,真相大白!

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

原因是Integer存在缓存,范围值-128到127,相当于就是一个字节byte的取值范围。
举个栗子:

Integer a=1,b=1;
System.out.println(a==b);

通过valueOf方法不难分析,答案就是true
好,回归正题,我们如何避免这个缓存机制呢?

public static void swap(Integer i1,Integer i2) throws NoSuchFieldException, IllegalAccessException{
        //TODO
        Field field = Integer.class.getDeclaredField("value");
        //暴力访问私有成员变量
        field.setAccessible(true);
        //int tmp = i1.intValue();
        Integer tmp = new Integer(i1.intValue());
        field.set(i1,i2.intValue());
        field.set(i2,tmp);
    }

根据valueOf源码:直接new出来Integer,不走判断逻辑,问题得以解决!
输出:

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

知识点总结

  1. 值传递和引用传递

Java中的数据类型分为两种为基本类型和引用类型。
函数传递引用类型:函数接收的是原始值的地址,所以原始值会变。
函数传递基本类型:函数接收的是原始值的副本,所以原始值不变。

  1. 自动装箱和拆箱

  2. Integer -128到127之间的缓存

  3. 反射:通过反射去修改private final变量

题外

通过这个面试题,想到了java基础篇之基本数据类型的取值范围如何获得?以及位运算符的相关操作,后续更新!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值