欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Integer的自动装箱与拆箱

程序员文章站 2024-03-07 13:04:45
...

装箱和拆箱

  • 装箱:将基本数据类型转换成封装类型。
  • 拆箱:将封装类型转换成基本数据类型。

自动装箱和自动拆箱

在jdk1.5开始增加了自动装箱和自动拆箱机制,就是为了方便基本类型和封装类型之间的互相转换。
下面来看看自动装箱(拆箱)和显示装箱(拆箱)的例子:

Integer a1 = 3;  // 自动装箱
Integer a2 = Integer.valueOf(3);  // 显示装箱

int a3 = new Integer(3);  // 自动拆箱
int a4 = new Integer(3).intValue();  // 显示拆箱

自动装箱 / 拆箱的实现

其实自动装箱或拆箱是通过编译器自动执行的,当然调用的方法还是一样的。下面来看看源码实现。以Integer为例:

Integer.valueOf(int i)

首先进入valueOf方法。这里先判断传入的值是否在IntegerCache.low和IntegerCache.high范围之内,如果在则从IntegerCache.cache数组中直接返回一个对象,否则就new一个新的对象。

public static Integer valueOf(int i) {
    // -128 < i < 127,返回一个缓存对象
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    // 否则新建一个对象
    return new Integer(i);
}

这里的IntegerCache是个私有内部静态类,具体看代码中的注释。这里可以清楚的知道上面说的缓存的范围是在-128~127之间,但是最大值可以通过虚拟机参数修改。

    private static class IntegerCache {
        static final int low = -128; // low默认为-128
        static final int high; // high的初始化在静态代码块中
        static final Integer cache[]; // 存放缓存对象的数组

        static {
            // 最高值可能由虚拟机参数设置
            int h = 127;
            // 这里可以通过VM参数-XX:AutoBoxCacheMax来设置high的值
            String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            // 判断是否设置了参数
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    // high不能小于127
                    i = Math.max(i, 127);
                    // high的最大值不能超过Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // 如果参数不能解析为int值,则直接忽视它
                }
            }
            // 在这里设置high的值,如果没有设置参数,那么它将是默认的127
            high = h;
            // 初始化cache数组,将容量设置为high - low,也就是刚好装下-128~127的Integer对象
            cache = new Integer[(high - low) + 1];
            int j = low;
            // 将-128~127的Integer对象都初始化,然后放在cache中
            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.intValue()

这个就没啥好说的啦,就是直接返回这个数值。

public int intValue() {
    return value;
}

下面来看一下可能出现的面试 / 笔试题:

        // Integer类型的实例
		Integer a1 = new Integer(127);
		Integer a2 = new Integer(127);
		Integer a3 = new Integer(128);
		// 基本数据类型
		int a4 = 128;
		// 自动装箱得到Integer类型的实例
		Integer a5 = a3.intValue();
		Integer a6 = 127;
		Integer a7 = 127;
		// 显示装箱得到Integer类型的实例
		Integer a8 = Integer.valueOf(128);

        // 这个肯定为false啦,因为a1和a2是两个不同的实例。两个实例用等号进行比较的话,会比较对象所引用的地址是否相同,这里肯定是不同的。
		System.out.println(a1 == a2);
        // 这里与上面类似,虽然a6会自动装箱为Integer类型,但这里还是两个不同的实例,所以不相等
		System.out.println(a1 == a6);
        // 因为a4是个基本类型,封装类型遇到基本类型会自动拆箱的,a3变为基本类型。两个基本类型进行比较直接比较内容是否相等就行啦,这里两个数值相等,所以为true。
		System.out.println(a3 == a4);
        // 这个与上面的类似,自动装箱类型遇到基本类型又会自动拆箱的。也为true。
		System.out.println(a4 == a5);
        // 这个就比较有意思了。两个都是自动装箱得到的Integer实例,因为Integer有个缓存机制,如果没有认真看,应该会认为是true,其实不然。
        // 因为这里的128超出了Integer的默认缓存范围(-128~127),所以在缓存数组中找不到这个Integer实例,只能重新创新一个新的Integer实例,这就变成了类似第一个的比较,所以为false
		System.out.println(a5 == a8);
        // 这里两个数都是127,在缓存范围内。所以会直接从缓存数组中取已经提前实例化好的对象,所以取的是同一个对象(引用地址也相同哦),自然结果是true啦。
		System.out.println(a6 == a7);

总结

  • 两个实例进行比较,不仅要内容相同,还要所引用的对象地址也相同,否则是不相同的(所以比较两个封装类型的对象一般使用equals)。
  • 封装类型遇到基本类型会自动拆箱,所以Integer实例与基本类型比较,只要内容相等,就是相等的。
  • Integer内有个缓存机制,为了对象的重用。范围在-128~127的整型通过自动装箱得到的对象是相同的(返回的是同一个对象),超出范围则不会相同(会new一个新的对象)。范围最大值可通过虚拟机参数-XX:AutoBoxCacheMax来设置。
相关标签: Integer