关于包装类的自动装拆箱问题

Java为每种基本数据类型都提供了对应的包装器类型。 

 

基本数据类型包装类基本数据类型包装类
byteBytefloatFloat
shortShortdoubleDouble
intIntegerbooleanBoolean
longLongcharCharacter

  Java SE5开始就提供了自动装箱的特性,如果要生成一个数值为10的Integer对象,不需要使用new 关键字,只需要这样就可以了:

Integer i = 100;

装箱就是自动将基本数据类型转换为包装器类型;拆箱就是自动将包装器类型转换为基本数据类型。其中,装箱过程是通过调用包装类的valueOf方法实现的,而拆箱过程是通过调用包装类的 xxxValue方法实现的。(xxx代表对应的基本数据类型)。上段代码即自动调用了Integer的valueOf()方法。包装类的自动装拆箱还有一个容易被忽略的问题,即包装类的cache数组。

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

// 大于127,新建对象。
Integer i5 = 128;
Integer i6 = 128;
System.out.println(i5 == i6);

以上代码的输出结果有些出人意料。true  false。

可能会有同学感到疑惑,两段代码似乎没什么区别,为什么输出结果大相径庭。其实答案就在包装类的valueOf()方法中。

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

从源码中可以得出,当Integer类的valueOf方法被调用时并不会直接new一个对象,而是首先对传入参数的值做了一个判断,决定了是否要从IntegerCache数组中获取返回值。下面我们一下看IntegerCache是什么。

    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) {
                try {
                    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);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;

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

            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

        private IntegerCache() {}
    }

IntegerCache是一个静态内部类,其维护了一个Integer数组,且数组长度微256,数组元素是尤其下标值封装的一个Integer对象。当Integer类的valueOf方法被调用时,程序首先会判断IntegerCache.cache数组中是否已存在同值的Integer对象,若存在,则直接从中获取返回,若不存在,直接新建Integer。

由此,就不难理解为什么分别新建两个值为127和值为128的Integer对象,“==”运算结果不一样了。值为127时,两次自动装箱的结果引用实际为同一对象,而参数值为128时,则是新建了两个不同的对象。Byte、Short、Integer、Long的cache的取值范围均为-128-127;Character包装类中cache的取值范围为0-127.

注意:当使用的new 关键字新建对象而不是自动装箱的情况下,程序不会从IntegerCache中获取,无论参数值是多少,都是新建的不同的对象。

Integer i3 = new Integer(100);
Integer i4 = new Integer(100);
System.out.println(i3 == i4);

输出结果为false.

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页