交换两个int型数据的静态方法

阅读更多

   

之前朋友面试遇到了一个挺有趣的问题,题目如下:

 

    public static void main(String[] args) throws Exception{
        int a = 1;
        int b = 2;
        swap(a, b);
        System.out.println("a is "+a+", b is "+b);
    }

 

   编写swap方法使a、b两个值交换数据,即a=2,b=1

   这在个人知识范围内,觉得不可能实现,找了一段写的比较好的解释,如下:

   java的基本数据类型共有8种,即int,short,long,byte,float,double,boolean,char(注意,并没有String的基本类型 )。

   这种类型的定义是通过诸如int a = 1;long b = 255L;的形式来定义的。

   如int a = 1;这里的a是一个指向int类型的引用,指向1这个字面值。这些字面值的数据,

   由于大小可知,生存期可知(这些字面值定义在某个程序块里面,程序块退出后,字段值就消失了),出于追求速度的原因,就存在于栈中。

 

   另外,栈有一个很重要的特殊性,就是存在栈中的数据可以共享。比如:

   我们同时定义:

 

   int a=1;

   int b=2;

 

   编译器先处理int a = 1;

   首先它会在栈中创建一个变量为a的引用,然后查找有没有字面值为1的地址,没找到,就开辟一个存放1这个字面值的地址,然后将a指向3的地址。

   接着处理int b = 2;在创建完b这个引用变量后,由于在栈中已经有2这个字面值,便将b直接指向2的地址。这样,就出现了a与b同时均指向2的情况。

 

   定义完a与b的值后,再令a = 4;

   那么,b不会等于4,还是等于2。在编译器内部,遇到时,它就会重新搜索栈中是否有4的字面值,如果没有,重新开辟地址存放4的值;

   如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。

   那怎么解决这个呢?

   贴代码:

   

public static void main(String[] args) throws Exception {
        Integer a = 1333;
        Integer b = 2333;
        swap(a, b);
        System.out.println("a is "+a+", b is "+b);
    }
    private static void swap(Integer x, Integer y) throws Exception {
        int z= x;
        Field field = Integer.class.getDeclaredField("value");
        field.setAccessible(true);
        field.set(x, y);
        field.set(y, z);
        System.out.println("x is "+x+", y is "+y);
    }

 

    将基本类型改为对象类型,这样是不是就好了呢?看上去应该没什么问题,输出结果也是正确的,可试试a=1,b=2呢!

    结果成了2 2,是不是觉得很怪异,JD反编译后如下:

 

    private static void swap(Integer x, Integer y) throws Exception {
        int z= x;
        Field field = Integer.class.getDeclaredField("value");
        field.setAccessible(true);
        field.set(x, y);
        field.set(y, Integer.valueOf(z));
        System.out.println("x is "+x+", y is "+y);
    }

 

    

   查看Integer源码valueOf(i)方法,就会发现原因了!

 

  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-128],field.set(x, y);这行代码会把缓冲池里面的值给修改了,将IntegerCache.cache[129]=IntegerCache.cache[130]=2

    所以导致a=b=2,怎么破呢?

    无非就是将获取的z值不走IntegerCache,那就直接new吧!修改代码

    field.set(y, z);改为field.set(y, new String(z));问题解决,可还是最好不要使用公用的IntegerCache,继续修改代码:

    

    public static void main(String[] args) throws Exception {
        Integer a = new Integer(1);
        Integer b = new Integer(2);
        swap(a, b);
        System.out.println("a is "+a+", b is "+b);
    }

 

    成功了。

    总结一下:

    一)int数据存储在常量池,地址在栈。

    二)Integer 定义的两个变量(如:integer a = 1; integer b = 2),它们公用一个IntegerCache。

你可能感兴趣的:(int,integer)