java Integer类的装箱拆箱解读

这是一个面试经常遇到的一个问题,先来看几个例子:
例1:

Integer i1=1234;
int i2=1234;
System.out.println(i1==i2);

输出结果为: true.
例2:

Integer i1=213;
Integer i2=213;
System.out.println(i1==i2);

输出结果为:false. 这是为什么呢?
例3:

Integer i1=127;
Integer i2=127;
System.out.println(i1==i2);

输出结果为:true.这又是为什么呢?
例4:

Integer i1=213;
Integer i2=new Integer(213);
System.out.println(i1==i2);

输出结果为:false;
例5:

Integer i1=123;
Integer i2=new Integer(123);
System.out.println(i1==i2);

输出结果为:false;

原因分析:
首先我们回到标题说一下JAVA的装箱拆箱:意思是当java程序需要将Integer类型当做int类型使用时,需要拆箱,将Integer类里的值取出来,作为一个int类型的值。我们知道java为每种基本数据类型都编写了一个封装类: byte,char,short,int ,long,float,double这几种基本数据类型都对应一个封装类:Byte,Short,Character,Short,Integer,Long,Float,Double. 我们现在专就Integer类与int做讨论,其他类似。

Integer类有一个域value,代表了该Integer对象的int值。当Integer对象需要当做Int类型时,就将其拆箱,取出这个value。这就是拆箱。装箱过程与拆箱相反:当我们需要一个Integer对象时,可以直接使用: Integer var=xxx. java的装箱就是通过方法: Integer Integer.valueOf(int xxx)返回一个数值为xxx的Integer对象。

接下来看例1:
第1行代码:用一个Integer i1=1234;等价与执行了:Integer i1 = Integer.valueOf(1234);//装箱
第3行代码: 当Integer需要和int比较时,首先将Integer转成Int,这就是拆箱,取出其Int值,两个int值都为1234,所以相等,输出true;

在分析例2之前首先了解Integer类的valueOf方法实现机制:

 public static Integer valueOf(int i) {
        assert IntegerCache.high >= 127;
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];//其中IntegerCache.low=-128,IntegerCache.high=127
        return new Integer(i);
    } 

从代码中可以看出:当i>=127或者小于-128时,new Integer(i),返回的是通过new 出来的一个值为i的Integer对象。而当i在-128到127之间是,返回的是一个IntegerCache.cache[]数组中的对应Integer对象,下面我们再来看看IntegerCache类在Integer类中的实现机制。

private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];

        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                int i = parseInt(integerCacheHighPropValue);
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);
        }

        private IntegerCache() {}
    }
  //这是Integer类中的一个私有静态类,所以所有Integer对象都应该共享着这一个类(虽然看不见(private))。该类的构造方法被私有化了,所以不能实例化该类。该类的其他代码全部是静态的,所以所有Integer对象都共享这这个类的每个域。在这里我们看到了Integer cache[]这个数组,而且该类在加载时就已经实例化了cache数组,chache数组是Integer类型的,每个元素都是一个Intger对象,并且数组第0个元素是值为-128的Integer对象,数组最后一个元素是值为127的Integer对象。回到valueOf方法中,当valueOf接受的参数在-128到127之间时,直接会返回该参数在cache数组中对应的那个Integer对象。否则new 一个Integer对象。

通过上面的解析,我们就自然明白了例2到例5的结果:
例2:
因为 Integer i1=213执行了Integer.valueOf(213),而由于213不在-128到127之间,所以就new Integer(213)并将该对象返回,同理,Integer i2=213实质也是 new Integer(213).由于两个new Integer(213)并不是同一个对象(内存地址肯定不一样,只是值一样罢了),所以i1==i2当然为false了,因为==比较的是内存地址。
例3:
因为127在-128到127之间,所以Integer.valueOf(127)返回的是 IntegerCache.cahe数组中对应值为127的那个元素,所以i1 和i2都指向的是同一个Integer对象(IntegerCache.cache是所有Integer对象共享的),所以i1==i2就是true;
例4和例5就很好理解了:一个是new出来的Integer对象,另一个要么是cache数组里的Integer对象,或者是new出来的,反正实质都是两个new出来的Integer对象比较,内存地址肯定不一样,所以值都为false.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章