• java的Integer中也会有缓存


    在上篇《java的自动拆箱会发生NPE》博客中接收了java中的Integer中的自动拆箱产生的NPE,其实对于所有的包装类来说都是一样的,都会产生这样的问题,大家需要举一反三,做学问学知识要懂得反思总结。

    一、前情回顾

    先回顾下上次的知识点,

    自动拆箱 实际调用的是intValue()方法

    自动装箱 实际调用的是valueOf(int i)方法

    其他的包装类,小伙伴们自己总结

    二、Integer的本地缓存

    好了话不多说,书接上回,开始这次的分享,上次说到在自动装箱的时候还大有玄机,这个玄机就是本地缓存。这个玄机在自动装箱的方法中,如下

    复制代码
    /**
         * 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) {
            if (i >= IntegerCache.low && i <= IntegerCache.high)
                return IntegerCache.cache[i + (-IntegerCache.low)];
            return new Integer(i);
        }
    复制代码

    先看下其方法说明吧,用我大学英语六级的水平给大家翻译下,献丑了大家莫怪,

    返回一个代表指定int的Integer对象,如果一个新的Integer实例不是必需的,这个方法通常使用构造方法来生成,另一方面,这个方法通常为了节省空间和实际会缓存一些经常使用的值

    这个方法会缓存[-128~127]间的值,也可能会缓存这个范围以外的值

    翻译的太差劲了,大体意思是如果参数在[-128,127]间则会从缓存中取,如果不在则直接生成Integer的实例。还有很重要的一点最大值可以配置。

    看方法的逻辑也是这样的,看下Integer初始化缓存的代码,在Integer中有静态内部类IntegerCache,代码

    复制代码
    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
                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循环,生成缓存
                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中存在[-128,127]范围内的的256个缓存Integer实例。

    三、验证本地缓存

    上面说到,在Integer中存在缓存,重要的一点是在调用valueOf()方法的时候才会校验缓存,valueOf方法共有以下几个

    重要声明,在使用构造方法的时候是没有缓存的,看构造方法

    复制代码
     /**
         * Constructs a newly allocated {@code Integer} object that
         * represents the specified {@code int} value.
         *
         * @param   value   the value to be represented by the
         *                  {@code Integer} object.
         */
        public Integer(int value) {
            this.value = value;
        }
    复制代码

    那么在验证的时候就不能使用构造方法的方式,需要使用自动装箱的方式。

    1、构造方法没有缓存

    复制代码
    public class TestIntegerConstruct {
        public static void main(String[] args) {
            Integer i1=new Integer(1);
            Integer i2=new Integer(1);
            System.out.println(i1==i2);
    
        }
    }
    复制代码

    打印结果为,

    false
    
    Process finished with exit code 0

    打印出来为false,说明i1和i2为两个不同的对象。

    2、valueOf()方法才有的缓存

    使用valueOf构造两个Integer对象,

    复制代码
    public class TestValueOf {
        public static void main(String[] args) {
            Integer i1=1;
            Integer i2=1;
            System.out.println(i1==i2);
        }
    }
    复制代码

    打印结果为,

    true
    
    Process finished with exit code 0

    说明i1和i2为同一个实例,这里使用的是==来判断,对引用对象来说判断的不正是其地址。

     

    多说一点,这里两个引用类型的比较,大家不要像我这里似的,使用“==”,请使用equals方法,使用“==”比较的是内存地址,在大部分情况下,内存地址肯定不相等,而使用equals方法就说不准了,equals方法比较的是什么?

    3、Integer的equals方法

    看下Integer的equals方法比较的是什么东西

    复制代码
    public boolean equals(Object obj) {
            if (obj instanceof Integer) {
                return value == ((Integer)obj).intValue();
            }
            return false;
        }
    复制代码

    看到没,搜先判断的是类型,然后调用其intValue方法,也就是拆箱,比较的是Integer中value的值,也就是数值的比较。

    四、总结

    本文,分享了Integer中的本地缓存,需要明白以下几个问题,

    1、什么时候会用到本地缓存?--调用valueOf方法的时候

    2、本地缓存的大小;--默认为[-128,127],最大值可设置

    3、equals方法比较的是什么;--比较的是值得大小,非内存地址

     

    往期推荐

    java的自动拆箱会发生NPE

    源码中的设计模式--单例模式

  • 相关阅读:
    (JavaEE) 多线程基础3——多线程的代码案例 (单例模式, 阻塞队列,定时器)详解!!!
    DOM中的node节点属性详解
    花体字母代表什么
    Flutter 匠心千刃 | SHA256 加密
    招聘信息管理|基于SpringBoot招聘信息管理系统
    RabbitMQ(消息队列)
    解决Pytest UnknownMarkWarning: Unknown pytest.mark.single - is this a typo?
    java计算机毕业设计在线影院系统MyBatis+系统+LW文档+源码+调试部署
    农业四情监测系统:科技助力农业智慧化
    一文深度解读边缘计算产业发展前景
  • 原文地址:https://www.cnblogs.com/teach/p/16152775.html