如何写一个方法交换两个Integer类型的值?

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinat_30160727/article/details/83790554

刚看到这个问题的时候,可能会觉得很简单,但是真正实现出来就会遇到一些奇怪的现象。下面我先我第一感觉的解决方法。
1.错误的版本(也是第一感觉)

/**
 * @author
 */
public class ObjectShallowSize {

    /**
    第一步
     * 交换两个integer类型的变量
     */
    public static void swap(Integer value1,Integer value2){
        //第二步定义临时变量tempt,将value1赋值给tempt
        Integer tempt = value1;
        //第三步 将value2赋值value1变量
        value1 = value2;
        //第四步 将tempt赋值给value2
        value2 = tempt;

    }
    public static void main(String[] args){

       Integer firstValue = 200;
       Integer anotherValue = 300;
        System.out.println("交换前:firstValue="+firstValue + "  anotherValue=" +anotherValue);
        **swap(firstValue,anotherValue);**
        System.out.println("交换后:firstValue="+firstValue + "  anotherValue=" +anotherValue);

    }

}

上面的方法并不能交换firstValue 和anotherValue 的值,我们来分析下原因。
在执行swap方法之前的firstValue 和anotherValue在堆中如下图:
在这里插入图片描述
执行到方法swap时,经历了三步,我们来分析下这三步分别有什么变化
第一步:
调用swap方法,会创建两个局部变量value1和value2,其分别指向堆中200和300的内存区域,这个过程并不会改变firstValue 和anotherValue的引用。
在这里插入图片描述

第二步:
Integer tempt = value1;定义tempt临时变量,tempt的应用和value1相同指向同一内存区域
在这里插入图片描述
第三步:
value1 = value2;改变了value1的应用指向300的内存。
在这里插入图片描述
第四步:
value2 = tempt;改变value2的应用指向tempt的应用的内存
在这里插入图片描述
经历过以上四个步骤,方法swap执行结束,但是我们可以看倒firstValue和anotherValue的应用始终没有改变,所以我们打印的结果中前后并没有变化,也就没有交换两个变量的值。

交换前:firstValue=200  anotherValue=300
交换后:firstValue=200  anotherValue=300

分析:以前,我们遇到过交换两个int类型的变量值,但是其实基本数据类型,这里是对象类型,并不能通过改变应用交换两个值。通过查看Integer的源码,我们可以知道内部也是使用int类型存储的,因此我们可以修改这个int的value。但是value属性是private类型的,因此我们需要通过反射去修改其值。
正确的版本:

public class ObjectShallowSize {

public static void swap(Integer value1, Integer value2) throws Exception {

    //反射获取value属性对象
    Field declaredField = Integer.class.getDeclaredField("value");
    declaredField.setAccessible(true);
    //这一步很重要,决定是不是从缓存中取,一定不能Integer val = value1.intValue();这么写
    Integer val = new Integer(value1.intValue());
    declaredField.set(value1,value2);
    declaredField.set(value2,val);
}
public static void main(String[] args) throws Exception {

   Integer firstValue = 200;
   Integer anotherValue = 300;
    System.out.println("交换前:firstValue="+firstValue + "  anotherValue=" +anotherValue);
    swap(firstValue,anotherValue);
    System.out.println("交换后:firstValue="+firstValue + "  anotherValue=" +anotherValue);

    }

}

第一步:
Integer val = new Integer(value1.intValue());
在这里插入图片描述
创建val变量,并且在堆中重新分配一块内存,其值是200
第二步:
declaredField.set(value1,value2);
在这里插入图片描述
修改value1引用指向内存的值为300
第三步:
declaredField.set(value2,val);
在这里插入图片描述
修改value2应用指向的内存值为200.
打印结果:

交换前:firstValue=200  anotherValue=300
交换后:firstValue=300  anotherValue=200

上面的 Integer val = new Integer(value1.intValue());这一步非常重要,如果直接value1.intValue(),那么对于-128~127内的整数是从缓存中取的,导致出现很奇怪的现象,如下图分析:
为了分析出结果,我们修改firstValue 和anotherValue的值分别为1和2
第一步:
Integer val = value1.intValue();该方法首先会判断int值是否在-128~127之间,是则直接从缓存中取,否则才会在堆中分配一块内存。
在这里插入图片描述
第二步:
declaredField.set(value1,value2);
在这里插入图片描述
第三步:
declaredField.set(value2,val);
在这里插入图片描述

从上面可以看出,value1和value2的值都是2了,这就是缓存引起的问题。

猜你喜欢

转载自blog.csdn.net/sinat_30160727/article/details/83790554
今日推荐