aCoder2013/blog

Java原生类型包装类初解析

aCoder2013 opened this issue · 0 comments

首先看一段代码

        Integer a = 126;
        Integer b  =126;
        Integer c = 129 ;
        Integer d = 129 ;
        System.out.println(a==b);
        System.out.println(c==d);

输出结果会是多少呢,相信每个人心中都会有自己的答案,倒不如直接运行一下看看:

true
false

现在就有了疑问,为什么两个输出的结果不一样呢,这里就设计到了Integer设计了,我们可以用javap命令反编译一下字节码,看看到底发生了什么:

 public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=5, args_size=1
         0: bipush        126
         2: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
         5: astore_1
         6: bipush        126
         8: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
        11: astore_2
        12: sipush        129
        15: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
        18: astore_3
        19: sipush        129
        22: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
        25: astore        4
        27: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
        30: aload_1
        31: aload_2
        32: if_acmpne     39
        35: iconst_1
        36: goto          40
        39: iconst_0
        40: invokevirtual #4                  // Method java/io/PrintStream.println:(Z)V
        43: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
        46: aload_3
        47: aload         4
        49: if_acmpne     56
        52: iconst_1
        53: goto          57
        56: iconst_0
        57: invokevirtual #4                  // Method java/io/PrintStream.println:(Z)V
        60: return

从字节码中可以看出是调用了Integer类的静态方法valueOf(),因此我们再进去Integer的源码研究一下:

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

那么这里的IntegerCache类有什么秘密呢,我们也进去看一下源码,IntegerCache是Integer的一个私有内部类,构造器也是
私有的,保证了安全性,通过源码可以看出,low的值默认为-128,修饰符为static final,因此不可再更改其值,而high
的值可以通过设置参数-XX:AutoBoxCacheMax来设置,同时内部维护了一个static finalInteger数组.

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.low并且小于IntegerCache.high的话,则直接返回缓存中的对象,
因此用==比较肯定是相等的,如果if的条件不成立的话,那么就会new一个新的Integer对象返回,
因此肯定是不相等的
对于Boolean则是内部维护了两个常量:

    public static final Boolean TRUE = new Boolean(true);
    public static final Boolean FALSE = new Boolean(false);

对于Short和Long其实和Integer的实现差不多,只不过缓存的范围写死在了代码里面:

 final int offset = 128;
        if (l >= -128 && l <= 127) { // will cache
            return LongCache.cache[(int)l + offset];
        }
        return new Long(l);

对于Double和Float来说,则是直接返回,不进行任何缓存的操作:

    public static Double valueOf(double d) {
        return new Double(d);
    }

Flag Counter