包装类缓存池浅析

我们先来看一段代码
public class Demo {
	public static void main(String[] args) {
		Integer i1 = 100;
		Integer i2 = 100;
		System.out.println(i1 == i2);

		Integer i3 = 1000;
		Integer i4 = 1000;
		System.out.println(i3 == i4);
	}
}

执行一下:

     
诶,为什么两个输出的结果会不一样呢?不应该全是true或者全false吗?
然而一个是true,一个是false,这是为什么呢?代码在哪里出现了不一样的东西呢?
所以我们找到.class文件来反编译一下,根据Java编译机制, .java文件在编译后会生成 .class文件,交给JVM去加载执行
public class Demo {
    public static void main(String[] args) {
        Integer i1 = Integer.valueOf(100);
        Integer i2 = Integer.valueOf(100);
        System.out.println(i1 == i2);

        Integer i3 = Integer.valueOf(1000);
        Integer i4 = Integer.valueOf(1000);
        System.out.println(i3 == i4);
    }
}

诶,果然发现编译器在编译我们的代码时动了一些手脚,它在我们声明的变量上加了valueOf()方法,那进一步来看一下valueOf()方法是造成不同输出结果的原因吗?
public static IntegervalueOf(inti) {
    if (i >= IntegerCache.low &&i <= IntegerCache.high)         //看一下是否在缓存的数组里
        return IntegerCache.cache[i + (-IntegerCache.low)];     //如果在,直接取数组里相应的对象返回
    return new Integer(i);                                      //不在缓存的数组里,直接new一个对象返回
}

我们发现,Integer的作者在写这个类时,为了避免重复创建对象节省内存,对Integer值做了缓存,如果这个值还在缓存范围内,直接返回缓存好的对象,否则new一个新的对象类返回,那究竟这个缓存到底缓存了什么呢?我们去看IntegerCsche这个类:
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
        /*
        *  检查虚拟机里有没有相应的配置,如果有,取该值;如果没有,取默认的127
        */
        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() {}
}

这是一个内部静态类,该类只能在Integer这个类的内部访问,这个类在初始化的时候,会去加载JVM的配置,如果有值,就用配置的值初始化缓存数组,否则就缓存-128到127之间的值。
再来看看之前的代码:



结论:我们在比较两个Integer对象时,无论是怎么声明的,都一定要使用equals取比较,不能用==。

引申:
8种基本类型的包装类和对象池

java中基本类型的包装类的大部分都实现了常量池技术,这些类是Byte,Short,Integer,Long,Character,Boolean,另外两种浮点数类型的包装类则没有实现。另外Byte,Short,Integer,Long,Character这5种整型的包装类也只是在对应值小于等于127时才可使用对象池,也即对象不负责创建和管理大于127的这些类的对象。以下是一些对应的测试代码:
public class Demo {
    public static void main(String[]args) {
        // 5种整形的包装类Byte,Short,Integer,Long,Character的对象,
        // 在值小于127时可以使用常量池
        Short s1= 127;
        Short s2= 127;
        System.out.println(s1==s2);// 输出true
        // 值大于127时,不会从常量池中取对象
        Short s3= 128;
        Short s4= 128;
        System.out.println(s3==s4);// 输出false
        // Character
        Character c1= 127;
        Character c2= 127;
        System.out.println(c1==c2);// 输出true
        // 值大于127时,不会从常量池中取对象
        Character c3= 128;
        Character c4= 128;
        System.out.println(c3==c4);// 输出false
        // Boolean类也实现了常量池技术
        Boolean bool1=true;
        Boolean bool2=true;
        System.out.println(bool1==bool2);// 输出true
        // 浮点类型的包装类没有实现常量池技术
        Double d1= 1.0;
        Double d2= 1.0;
        System.out.println(d1==d2);// 输出false
    }
}

看一下Console:
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值