zoukankan      html  css  js  c++  java
  • 由自动装箱和拆箱引发我看Integer源码

    背景和问题

      在看别人整理的资料时,看到如下一段代码:

    package com.sitech.test;
    /**
     * 自动装箱和拆箱 jdk1.6
     * @author liaowp
     *
     */
    public class TestInteger {
    
        public static void main(String[] args) {
            Integer i1 = 80, i2 = 80, i3 = 999, i4 = 999;
            System.out.println(i1 == i2);//true
            System.out.println(i3 == i4);//false
        }
    }

      如果没有看过源码的同学肯定觉的答案要么是2个true要么是2个false。我刚看到这一段代码的时候也觉的是2个true,感觉自己100%确定,不过真正运行之后才发现傻眼了,一个true一个false,这是Bug吧。其实LZ以前看过一部分Integer源码了,但是现在想想好像看的不认真,尴尬了。于是被这个问题触发了LZ要认真看一次Integer源码了(我要认真了,哈哈)。

      我们还是回到上面那个问题吧,先把问题解决了在吹nb。我们可以看到上面的代码4个变量都是Integer的引用,所以输出的==运算比较的不是Integer值而是Integer引用。装箱的本质是什么呢?当我们给一个Integer对象赋一个int值的时候,会调用Integer类的静态方法valueOf,我们看一看valueOf方法就知道为什么会有这样的结果了。

        /**
         * Returns an {@code Integer} instance representing the specified
         * {@code int} value.  If a new {@code Integer} instance is not
         * required, this method should generally be used in preference to
         * the constructor {@link #Integer(int)}, as this method is likely
         * to yield significantly better space and time performance by
         * caching frequently requested values.
         *
         * This method will always cache values in the range -128 to 127,
         * inclusive, and may cache other values outside of this range.
         *
         * @param  i an {@code int} value.
         * @return an {@code Integer} instance representing {@code i}.
         * @since  1.5
         */
        public static Integer valueOf(int i) {//是一个静态方法 IntegerCache是一个内部类
            assert IntegerCache.high >= 127;//断言  参考http://lavasoft.blog.51cto.com/62575/43735/
            if (i >= IntegerCache.low && i <= IntegerCache.high)//如果i大于对于IntegerCache.low()且i小于等于IntegerCache.high
                return IntegerCache.cache[i + (-IntegerCache.low)];//直接从缓存取出来
            return new Integer(i);//新创建一个Integer对象
        }

      从上面的代码中我们可以看出Integer维持了一个缓存系统,如果在缓存的范围内直接取出来就好了,如果不在的就要创建新的Integer对象。但是具体缓存范围是什么的,我们在深入进去看看:

        /**
         * 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 -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;//最小值是-128
            static final int high;//最高
            static final Integer cache[];//缓存数组  这三个都final,不可修改的
    
            static {//静态代码块   静态代码块会比改造方法先执行
                // high value may be configured by property
                int h = 127;//默认的
                String integerCacheHighPropValue =//定义一个String 
                    sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");//取得设置的值
                if (integerCacheHighPropValue != null) {//如果设置了就用设置的值
                    int i = parseInt(integerCacheHighPropValue);//把String转换为int
                    i = Math.max(i, 127);//获得i和127的更大的一个,其实是不能小与默认的
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low));//如果取的小的那个,不能超过Integer的最大值+low
                }
                high = h;//最大值为127
    
                cache = new Integer[(high - low) + 1];//创建缓存数组大小
                int j = low;//最小值
                for(int k = 0; k < cache.length; k++)
                    cache[k] = new Integer(j++);//缓存初始化
            }
    
            private IntegerCache() {}//私有构造
        }

    问题解决

    Integer的缓存

      看完之后我相信基本都知道为啥一开始的那一段代码会这样了,我现在做一个小的总结,Integer里面有一个内部类IntegerCache,是用来做缓存优化性能的。默认缓存了-128到127中间的数字,据说这些使的比较频繁。其实java里面好多的类都有这样的优化。如果在-128-127之间的就直接拿缓存的,不在的就new一个Integer所以这也就解释了上面的那个问题了嘛

      本来还想把整个类都分析一遍的,后面看了看别人的分析的发现自己在的分析已经作用不大了,如果想往完整的看Integer类的分析,LZ推荐http://www.cnblogs.com/vinozly/p/5173477.html

  • 相关阅读:
    OpenJDK源码研究笔记(十二):JDBC中的元数据,数据库元数据(DatabaseMetaData),参数元数据(ParameterMetaData),结果集元数据(ResultSetMetaDa
    Java实现 LeetCode 257 二叉树的所有路径
    Java实现 LeetCode 257 二叉树的所有路径
    Java实现 LeetCode 257 二叉树的所有路径
    Java实现 LeetCode 242 有效的字母异位词
    Java实现 LeetCode 242 有效的字母异位词
    Java实现 LeetCode 242 有效的字母异位词
    Java实现 LeetCode 241 为运算表达式设计优先级
    Java实现 LeetCode 241 为运算表达式设计优先级
    Java实现 LeetCode 241 为运算表达式设计优先级
  • 原文地址:https://www.cnblogs.com/liaoweipeng/p/6263091.html
Copyright © 2011-2022 走看看