自动装箱

约 725 字大约 2 分钟

自动装箱

代码

public class AutoBox {
    public static void main(String[] args) {
        Integer a = 1;
        Integer b = 2;
        Integer c = 3;
        Integer d = 3;
        Integer e = 321;
        Integer f = 321;
        Long g = 3L;
        System.out.println(c == d);
        System.out.println(e == f);
        System.out.println(c == (a + b));
        System.out.println(c.equals(a + b));
        System.out.println(g == (a + b));
        System.out.println(g.equals(a + b));
    }
}

享元

Java享元代码

  /**
  * Cache to support the object identity semantics of autoboxing for values between
  * -128 and 127 (inclusive) as required by JLS.
  *
  * The cache is initialized on first usage.  The size of the cache
  * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
  * During VM initialization, java.lang.Integer.IntegerCache.high property
  * may be set and saved in the private system properties in the
  * sun.misc.VM class.
  */

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;
        // 获取AutoBoxCacheMax缓存的最大值
        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() {}
}
  • System.out.println(c == d);测试结果为 true,Integer-128~127使用了享元设计模式,底层是同一个对象。
  • System.out.println(e == f);测试结果为 false,不在享元数据内。

字节码

Integer#intValue

  • System.out.println(c == (a + b));结果为 true,享元数据3转换成int,并将享元数据1和2转换成int后进行累加,进行对比,对比数据都是int类型。
83 aload_3
84 invokevirtual #8 <java/lang/Integer.intValue>
87 aload_1
88 invokevirtual #8 <java/lang/Integer.intValue>
91 aload_2
92 invokevirtual #8 <java/lang/Integer.intValue>
95 iadd
96 if_icmpne 103 (+7)
99 iconst_1
100 goto 104 (+4)
103 iconst_0

Integer#equals

  • System.out.println(c.equals(a + b));这个为 true,享元数据1和3转换成int,在Integer.valueOf转换成了享元数据,所以有无Integer.equals结果都为true。
110 aload_3
111 aload_1
112 invokevirtual #8 <java/lang/Integer.intValue>
115 aload_2
116 invokevirtual #8 <java/lang/Integer.intValue>
119 iadd
120 invokestatic #2 <java/lang/Integer.valueOf>
123 invokevirtual #9 <java/lang/Integer.equals>
// 其结果使用了享元,即使不使用equals结果也为true
//     if (obj instanceof Integer) {
//       return value == ((Integer)obj).intValue();
//     }
//     return false;
// 所以结果为true

i2l

  • System.out.println(g == (a + b));结果为true,对于享元数据1和2转成int进行累加,并将将int转换为long,进行数据对比,对比的数据都是long类型。
aload 7
157 invokevirtual #11 <java/lang/Long.longValue>
160 aload_1
161 invokevirtual #8 <java/lang/Integer.intValue>
164 aload_2
165 invokevirtual #8 <java/lang/Integer.intValue>
168 iadd
169 i2l
// 将int转换为long
170 lcmp
171 ifne 178 (+7)
174 iconst_1
175 goto 179 (+4)
178 iconst_0
// 将int结果变为long(i2l),进行对比

Integer != Long

  • System.out.println(g.equals(a + b));结果为 false,享元数据1和2转换成int,累加,在转换成享元数据3,而Long是不进行享元存储的,这里进行对比的时候,Integer != Long
132 aload 7
134 aload_1
135 invokevirtual #8 <java/lang/Integer.intValue>
138 aload_2
139 invokevirtual #8 <java/lang/Integer.intValue>
142 iadd
143 invokestatic #2 <java/lang/Integer.valueOf>
146 invokevirtual #10 <java/lang/Long.equals>

Long.equals(Integer);
public boolean equals(Object obj) {
    if (obj instanceof Long) {
      return value == ((Long)obj).longValue();
    }
    return false;
}