Java 装箱 与 缓存池概念

1,710 阅读1分钟

装箱拆箱

自动装箱:可以直接把基本数据类型的值或者变量赋值给包装类

自动拆箱:可以把包装类的变量直接赋值给基本数据类型

public class PackegeClass {
    public static void main(String[] args) {
        int a = 12 ;
        Integer a1 = 12 ;  // 自动装箱
        Integer a2 = a ;   // 自动装箱
        Integer a3 = null; // 引用数据类型的默认值可以为null

        Integer c = 100 ;
        int c1 = c ;      // 自动拆箱

        Integer it = Integer.valueOf(12);  	// 手工装箱!
        // Integer it1 = new Integer(12); 	// 手工装箱!
        Integer it2 = 12;

        Integer it3 = 111 ;
        int it33 = it3.intValue(); // 手工拆箱
    }
}

自动装箱反编译后底层调用 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);
}

自动拆箱调用 java.lang.Integer#intValue,源码:

public int intValue() {
    return value;
}

缓存池

new Integer(123) 与 Integer.valueOf(123) 的区别在于:

  • new Integer(123):每次都会新建一个对象

  • Integer.valueOf(123):会使用缓存池中的对象,多次调用取得同一个对象的引用

    Integer x = new Integer(123);
    Integer y = new Integer(123);
    System.out.println(x == y);    // false
    Integer z = Integer.valueOf(123);
    Integer k = Integer.valueOf(123);
    System.out.println(z == k);   // true
    

valueOf() 方法的实现比较简单,就是先判断值是否在缓存池中,如果在的话就直接返回缓存池的内容。编译器会在自动装箱过程调用 valueOf() 方法,因此多个值相同且值在缓存池范围内的 Integer 实例使用自动装箱来创建,那么就会引用相同的对象 而包装类并不是都有缓存的,例如Double和Float就没有

Java中基本数据类型byte、short、char、int、long、float、double、boolean有对应的封装类型:Byte、Short、Character、Integer、long、Float、Double,Boolean其中Byte、Short、Character、Integer、Long、Boolean都实现了常量池缓存。Byte、Short、Character、Integer、Long通过静态内部Cache类来实现一定范围(下面列出缓存范围)内的数据缓存,而Boolean通过两个静态常量TRUE、FALSE来实现数据缓存。

基本类型对应的缓存池如下:

  • Boolean values true and false
  • all byte values
  • Short values between -128 and 127
  • Long values between -128 and 127
  • Integer values between -128 and 127
  • Character in the range \u0000 to \u007F (0 and 127)

在 jdk 1.8 所有的数值类缓冲池中,Integer 的缓存池 IntegerCache 很特殊,这个缓冲池的下界是 -128,上界默认是 127,但是上界是可调的,在启动 JVM 时通过 AutoBoxCacheMax=<size> 来指定这个缓冲池的大小,该选项在 JVM 初始化的时候会设定一个名为 java.lang.IntegerCache.high 系统属性,然后 IntegerCache 初始化的时候就会读取该系统属性来决定上界

Integer x = 100;				// 自动装箱,底层调用 Integer.valueOf(1)
Integer y = 100;
System.out.println(x == y);   	// true

Integer x = 1000;
Integer y = 1000;
System.out.println(x == y);   	// false,因为缓存池最大127

int x = 1000;
Integer y = 1000;
System.out.println(x == y);		// true,因为 y 会调用 intValue 【自动拆箱】返回 int 原始值进行比较