Skip to content

Java原生类型包装类初解析 #14

@aCoder2013

Description

@aCoder2013

首先看一段代码

 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions