Java基本类型的装箱

JDK:1.8

/**
 * 用于测试基本数据类型的自动拆箱和自动装箱
 */
public class AutoBox {

    /**
     * 测试整型的自动拆箱和缓冲
     */
    static class TestInt{

        public static void main(String[] args){

            Integer integer = new Integer(100);
            Integer integer1 = 100;
            Integer integer2 = 100;

            System.out.println(integer == integer1);//false
            System.out.println(integer1 == integer2);//true
            System.out.println(integer == integer2);//false
        }

        /*
        这个是上面主函数的字节码,现在来分析为什么输出是如此:
        public static void main(java.lang.String[]);
            Code:
               0: new           #2                  // class java/lang/Integer
               3: dup
               4: bipush        100
               6: invokespecial #3                  // Method java/lang/Integer."<init>":(I)V
               //使用new在堆里面实例化一个integer对象
               9: astore_1
              10: bipush        100
              12: invokestatic  #4                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
              //以100为参数调用integer类的静态方法
              15: astore_2
              16: bipush        100
              18: invokestatic  #4                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
              //以100为参数调用integer类的静态方法
              21: astore_3
              22: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
              25: aload_1
              26: aload_2
              27: if_acmpne     34
              30: iconst_1
              31: goto          35
              34: iconst_0
              35: invokevirtual #6                  // Method java/io/PrintStream.println:(Z)V
              38: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
              41: aload_2
              42: aload_3
              43: if_acmpne     50
              46: iconst_1
              47: goto          51
              50: iconst_0
              51: invokevirtual #6                  // Method java/io/PrintStream.println:(Z)V
              54: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
              57: aload_1
              58: aload_3
              59: if_acmpne     66
              62: iconst_1
              63: goto          67
              66: iconst_0
              67: invokevirtual #6                  // Method java/io/PrintStream.println:(Z)V
              70: return
         在我们使用自动装箱来进行实例化integer对象时,第12、18行都是调用的integer类的静态方法valueOf,也就是说,导致
         integer1与integer2指向同一个对象,而与integer指向不同对象的原因就是在这里,现在分析valueOf源码:
         public static Integer valueOf(int i) {
            if (i >= IntegerCache.low && i <= IntegerCache.high)
                return IntegerCache.cache[i + (-IntegerCache.low)];
            return new Integer(i);
         }
         从上面的源码看出来在传入的值处于某个区间时,返回的是同一个对象,只有在超出这个范围时才是在堆里面创建一个新的对象
         也就是说integer1与integer2地址相同是因为100处于这个区间里面,现在继续分析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:告诉我们这个可以配置?在类文档里面找到可以使用-XX:AutoBoxCacheMax=<size>配置
                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);//high - low + 1 = Integer.MAX_VALUE;->high = Integer.MAX_VALUE - (-low) -1
                    } catch( NumberFormatException nfe) {}
                }
                high = h;
                //这个就是被缓存的整型对象数组
                cache = new Integer[(high - low) + 1];
                int j = low;
                //在这里进行了实例化,所以只要是配置范围里面的对象都已经被事先创建出来了。
                for(int k = 0; k < cache.length; k++)
                    cache[k] = new Integer(j++);
            }
        }
        综合上面的分析,如果我们使用自动装箱的方式,相当于隐式调用了valueOf函数,而这个函数会先判断该数值是否已经在配置
        的缓存里面,如果在就直接返回,如果不在才创建新的对象,所以这就是上面输出的解释了。
        剩下的基本数据类型包装的缓存如下:
        Boolean:没有,一个正负要撒子缓存嘛。
        Byte:缓存-128-127,恐怖,全部被缓存了,每一个Byte都被缓存了。
        private static class ByteCache {
            private ByteCache(){}
            static final Byte cache[] = new Byte[-(-128) + 127 + 1];
            static {
                for(int i = 0; i < cache.length; i++)
                    cache[i] = new Byte((byte)(i - 128));
            }
        }
        Character:缓存0-127
        private static class CharacterCache {
            private CharacterCache(){}
            static final Character cache[] = new Character[127 + 1];
            static {
                for (int i = 0; i < cache.length; i++)
                    cache[i] = new Character((char)i);
            }
        }
        Short: 缓存-128-127
        private static class ShortCache {
            private ShortCache(){}
            static final Short cache[] = new Short[-(-128) + 127 + 1];
            static {
                for(int i = 0; i < cache.length; i++)
                    cache[i] = new Short((short)(i - 128));
            }
        }
        Float:没有!
        Double:没有!
        Long:缓存-128-127
        private static class LongCache {
            private LongCache(){}
            static final Long cache[] = new Long[-(-128) + 127 + 1];
            static {
                for(int i = 0; i < cache.length; i++)
                    cache[i] = new Long(i - 128);
            }
        }
        总结:只有int的范围可以配置,以后再有人问你int类型自动拆箱和装箱的过程,先问他-XX:AutoBoxCacheMax=<size>参数配置
        的是啥,哈哈哈哈。(size大于127才有效,否则都是默认的127)
         */
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章