带你轻松解读Integer自动装箱源码

25 篇文章 0 订阅
11 篇文章 0 订阅
一、最近总结

最近这几天不用加班,时间比较多,在微信读书阅读《编写高质量代码-改善Java程序的151个建议》这本书,截止现在读到5%左右,给我的感觉就是干货满满,作者以他丰富的经验,将解决问题之后的总结,写入该书之中,让读者收益匪浅呀=-=

二、抛砖引玉
1、请看下面程序,智慧的你,请在控制台分次输入:127、128、555,你会觉得程序运行结果是什么呢?
public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        while (input.hasNextInt()) {
            int ii = input.nextInt();
            System.out.println("\n ==========" + ii + "的相等判断=========");
            Integer i = new Integer(ii);
            Integer j = new Integer(ii);
            System.out.println("new产生Integer对象的比较:" + (i == j));

            //基本类型转换为包装类型后的比较
            i = ii;
            j = ii;
            System.out.println("基本类型转换成Integer对象的比较:" + (i == j));

            //通过静态方法生成的一个实例
            i = Integer.valueOf(ii);
            j = Integer.valueOf(ii);
            System.out.println("valueOf产生Integer对象的比较:" + (i == j));

        }
    }
2、运行结果
输入值程序运行结果
127在这里插入图片描述
128在这里插入图片描述
555在这里插入图片描述
3、问题来了:

对于基本类型转换成Integer对象、和通过valueOf产生Integer对象的比较(可以总结为:通过装箱生成的对象
为什么输入127返回结果都是true,而128、555都是返回false呢

4、解答来了:

(1)对于new产生的对象
new声明的就是要生成一个新的对象,没二话,这是两个对象,地址肯定不等,比较结果为false。
(2)通过装箱产生的对象
Integer的装箱动作,是通过valueOf方法实现的,且让我们浏览一下jdk1.8该方法源码吧

valueOf源码解析:

/**
     * Returns an Integer instance representing the specified int value.
     * If a new Integer instance is not  required, 
     * this method should generally be used in preference to
     * the constructor Integer(int), as this method is likely
     * to yield significantly better space and time performance by
     * caching frequently requested values.
     * 翻译:返回表示指定int值的Integer实例。
     * 
     *
     * This method will always cache values in the range -128 to 127,
     * inclusive, and may cache other values outside of this range.
     * 翻译:此方法将始终缓存-128到127(包括端点)范围内的值,并可以缓存此范围之外(需要进行jdk参数设置)的其他值。
     *
     * @param  i an int value.
     * @return an {@code Integer} instance representing {@code i}.
     * @since  1.5
     */
    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

翻译并加上自己的理解:

1、如果不需要产生新的Integer实例,通常应优先使用此方法(优先于使用构造函数Integer(int)),因为这个方法通过缓存频繁请求的值(整形池),将空间获得更好的空间和时间性能(显着提高)。
2、此方法将始终缓存-128到127(包括端点)范围内的值,并可以缓存此范围之外(需要设置jdk初始化参数)的其他值。
3、(1)入参:一个int值 (2) 返回值:返回一个Integer的实例 (3)方法始于jdk1.5

白话文理解:如果要将-128到127(包括断点)的int类型的值转换为Integer对象,默认是从cache缓存数组中获取的(即整形池

IntegerCache.cache源码解析:

/**
     * Cache to support the object identity semantics of autoboxing for values between
     * -128 and 127 (inclusive) as required by JLS.
     *
     * The cache is initialized on first usage.  The size of the cache
     * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
     * During VM initialization, java.lang.Integer.IntegerCache.high property
     * may be set and saved in the private system properties in the
     * sun.misc.VM class.
     */

    private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];
        static {
            // [-128,127]之外的int值,想要每次new Integer(int i)从缓存池中获取,则需要配置jdk初始化参数
            // 1、默认最大值是127
            int h = 127; 
            // 2、获取用户设置的jdk初始化high值
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            // 3、如果用户配置了初始化值   
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    // 4、从(默认值127、用户自定义值)中取出值最大者
                    i = Math.max(i, 127);
                    // 5、从(4中最大值,Integer.MAX_VALUE)中取出最小者
                    // 注意:在java中,数组的大小(元素数量),最多只能有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;
			// 6、初始化缓存池大小
            cache = new Integer[(high - low) + 1];
            int j = low;
            // 6、往缓存池中填数据
            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() {}
    }

翻译并加上自己的理解:

1、根据java规范JLS(http://java.sun.com/docs/books/jls/): 缓存池支持自动装箱之间的int值为范围-128和127(含)
2、缓存池(整形池)在首次使用时进行初始化。 缓存池的大小可以通过配置{ -XX:AutoBoxCacheMax = high值}进行控制。
在虚拟机初始化期间,java.lang.Integer.IntegerCache.high属性,可以设置并保存在sun.misc.VM类私有系统属性中。

白话文理解就是:缓存池默认缓存的int值范围为:-128到127(包含端点),可以通过设置-XX:AutoBoxCacheMax = value来控制缓存值范围。

三、总结

工作上经常用到的Integer,不看源码还真的不知道有这么多奥妙,这不,看了valueOf的源码之后,得到一个高效的代码技巧:


    如果不需要产生新的Integer实例,自动装箱应优先使用 valueOf(int i) ,这将使你写得代码有更好的空间和时间性能

看完这篇文章,你get到了吗???

四、说明:

本博客源码jdk版本为1.8

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值