Integer常量池

来源:互联网 发布:员工培训软件 编辑:程序博客网 时间:2024/05/20 00:49

在Java中有8中基本数据类型,基本类型是分配在栈空间上的,Java为我们提供了分配在堆栈空间的8种基本类型的包装类(Byte、Short、Integer、Long、Float、Double、Boolean、Character),这些包装类的实例对象除了包装的数据不一样外,其他的没有很明显的差别。

 就以Integer为例,各个Integer对象的差别在于包装的int类型的值不同而已,假设Java中的Integer类只是简单的对int值进行包装,这样会出现什么问题呢?若程序中需要使用大量包装了相同int值的Integer对象,这种情况会对内存造成极大浪费,对于没有什么外部状态的Integer对象,包装了相同int值的Integer对象在程序中出现一次就行。

 因此sun公司对Integer做了特殊的处理,对Integer类应用了享元模式,享元模式它的优点在于,通过共享一些对象降低内存中相同对象的数量。使用了设计模式固然会对程序带来诸多好处,但它也会是程序付出一些代价。想象一下int类型从0x80000000到0x7fffffff如果把所有这些数字包装成共享对象,那需要的对象的数量将是多么的庞大,恐怕还不如不进行处理呢,另外在程序中有很多用不上(在项目中从来那没见那个程序会把所有的int值用个遍的)。因此Integer只对包装了int值在-128-127这个范围的Integer对象做了共,从下面这段代码可以的运行结果可以看出。

程序遍历了从0x80000000到0x7fffffff所有的int类型的值,并把每一个数组封装成了两个对象,如果这两个对象属于同一个对象就打印出来,

public class Test1 {
 public static void main(String[] args) {
  for (int i = Integer.MIN_VALUE;i < Integer.MAX_VALUE;i++) {
   Integer i1 = i;
   Integer i2 = i;
   if (i1 == i2)
    System.out.print(i + " ");
  }
 }
}

打印的结果是:-128 -127 -126 -125 -124 -123 -122 -121 -120 -119 -118 -117 -116 -115 -114 -113 -112 -111 -110 -109 -108 -107 -106 -105 -104 -103 -102 -101 -100 -99 -98 -97 -96 -95 -94 -93 -92 -91 -90 -89 -88 -87 -86 -85 -84 -83 -82 -81 -80 -79 -78 -77 -76 -75 -74 -73 -72 -71 -70 -69 -68 -67 -66 -65 -64 -63 -62 -61 -60 -59 -58 -57 -56 -55 -54 -53 -52 -51 -50 -49 -48 -47 -46 -45 -44 -43 -42 -41 -40 -39 -38 -37 -36 -35 -34 -33 -32 -31 -30 -29 -28 -27 -26 -25 -24 -23 -22 -21 -20 -19 -18 -17 -16 -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 

也就是说sun只对一个字节内的数值的Integer对象做了共享。

 

sun对Integer类怎么样进行处理的呢???

直接搞出来-128到127的对象缓存起来,放在map中,当实例化-128和127之间的Integer对象时,直接拿出缓存中的对应的对象(这种方式付出的代价,就是包装了-128到127这些Integer对象占用的内存),翻开java.lang.Integer的源代码,找到在Integer类中有一个私有内部类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) {
                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 = h;


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


        private IntegerCache() {}
    }

这个类的第三行处有个名字叫cache的Integer数组,相当于我们假想的map,数组的长度为(high - low) + 1,就是一个字节内,low为cache值的下限-128,high为cache值的上限127,


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

上面这段代码就是直接new出来-128到127的255个对象缓存起来,做成一个常量池,在看看Integer中有一个通过一个int值拿到对应的Integer对象的静态方法valueOf

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

里面的实现就是先判断一下数字是不是在-128与127之间,是的话直接返回cache中对应的Integer对象,否而new出来对应对象并返回,现在的硬件配置越来越高,内存越来越大,这一点内存相对之下是非常微小的,在空间与效率之间,java编写api的人员选择了效率高占用空间的方式