Java包装类缓存

Java基本类型的包装类的大部分都实现了常量池技术,即Byte,Short,Integer,Long

这四种包装类默认创建了数值[-128,127]的相应类型的缓存数据,Character创建了数值在[0,127]范围的缓存数据,Boolean直接返回true或者false。超出此范围会创建新的对象。

public static Boolean vatue0f(boolean b){
    return(b?TRUE:FALSE);
}
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);
    }
}

浮点类型的包装类Float和Double没有实现常量池技术

缓存区间设置为[-128,127]的原因:

https://github.com/Snailclimb/JavaGuide/issues/461

由于Integer变量是对一个Integer对象的引用,所以两个通过new生成的Integer变量永远是不相等的(在堆内存地址不同)。

Integer i = new Integer(100);
Integer j = new Integer(100);
System.out.print(i == j); //false

非new生成的Integer变量和new Integer()生成的变量比较时,结果为false。(非new生成的 Integer变量指向的是java常量池中的对象,而new Integer()生成的变量指向堆中新建的对象,两者在内存中的地址不同)

Integer b = new Integer(100);
Integer c=100;
System.out.println(b == c); // false

对于两个非new生成的Integer对象,进行比较时,如果两个变量的值在区间-128到127之间,则为true,如果不在这区间,则为false

Integer i = 100;
Integer j = 100;
System.out.print(i == j); //true
Integer i = 128;
Integer j = 128;
System.out.print(i == j); //false

因为当值在 -128 ~ 127之间时,java会进行自动装箱,然后会对值进行缓存,如果有相同的值,会直接在缓存中取出使用。缓存是通过Integer的内部类IntegerCache来完成的。当值超出此范围,会在堆中 new出一个对象来存储。

给一个Integer对象赋一个int值的时候,会调用Integer类的静态方法valueOf

Integer i=30;在编译的时候会直接将30封装为Integer。

i=Integer.valueOf(30);会使用常量池中的对象。

源码:

public static Integer valueOf(String s, int radix) throws NumberFormatException
{
    return Integer.valueOf(parseInt(s,radix));
}
/**
* (1)在-128~127之内:静态常量池中cache数组是static final类型,该对象会被存储于静
态常量池中。
* cache数组里面的元素不是static final类型,而是cache[k] = new Integer(j++),
* 这些元素是存储于堆中,只是cache数组对象存储的是堆中的Integer对象的地址
*
* (2)在-128~127 之外:在堆中新建一个 Integer对象,并返回。
*/
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);
}

IntegerCache是Integer的内部类,源码:

/**
* 缓存支持自动装箱的对象标识语义 -128和127(含)。
* 缓存在第一次使用时初始化。 缓存的大小可以由-XX:AutoBoxCacheMax = <size>选项控制。
* 在VM初始化期间,java.lang.Integer.IntegerCache.high属性可以设置并保存在私有系统
属性中
*/
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() {}
}

最大边界可以通过-XX:AutoBoxCacheMax进行配置

Integer a=newInteger(48);
Integer b=newInteger(48);
Integer c=newInteger(0);
System.out.println("a=b+c"+(a==b+c));

由于+不适用于Integer对象,所以b,c会先自动拆箱进行数值相加,又由于Integer对象无法与数值直接比较,所以a自动拆箱为int,最终转为48==48 

上一篇:verilog有符号数加减法----正负128


下一篇:基本数据类型