Boolean、Byte、Short、Integer、Long、Character 的缓存机制

装箱都是执行valueOf方法:如果有缓存将判定是否在缓存范围内,否则new。

拆箱则是执行xxxValue方法!<floatValue、longValue、intValue。。。>

    public static boolean isSuspend(Double code) {
        return code == (int) 1;
    }

    public static void main(String[] args) {
        isSuspend(2d);
    }

入参先做装箱处理Double.valueOf;再做拆箱处理Double.doubleValue。
说明:拆箱与当前自己的包装类有关!

Java 语言规范中的缓存行为

在 Boxing Conversion 部分的Java语言规范(JLS)规定如下:

详情可见: https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.7 下的 【5.1.7. Boxing Conversion】、【5.1.8. Unboxing Conversion】

if the value p being boxed is an integer literal of type int between -128 and 127 inclusive (§3.10.1), or the boolean literal true or false (§3.10.3), or a character literal between '\u0000' and '\u007f' inclusive (§3.10.4), then let a and b be the results of any two boxing conversions of p. It is always the case that a == b.
如果一个变量 p 的值属于:-128至127之间的整数,true 和 false的布尔值,’u0000′ 至 ‘u007f’ 之间的字符中时,将 p 包装成 a 和 b 两个对象时,可以直接使用 a == b 判断 a 和 b 的值是否相等。

A boxing conversion may result in an OutOfMemoryError if a new instance of one of the wrapper classes (BooleanByteCharacterShortIntegerLongFloat, or Double) needs to be allocated and insufficient storage is available.

5.1.7 章节阐述: 

  1. 当内存空间不足以分配时,出现OutOfMemoryError; 
  2. 对于除 float、double外的的基本数据类型在自动装箱时有缓存Cache; 
  3. 在float、double装箱时,需要关注是否是NaN(Not-a-Number)

5.1.8 章节在关于拆箱的描述中: 如果为null时,将抛出NullPointerException.

Double:

    /**
     * A constant holding a Not-a-Number (NaN) value of type
     * {@code double}. It is equivalent to the value returned by
     * {@code Double.longBitsToDouble(0x7ff8000000000000L)}.
     */
    public static final double NaN = 0.0d / 0.0;


Float:

   /**
     * A constant holding a Not-a-Number (NaN) value of type
     * {@code float}.  It is equivalent to the value returned by
     * {@code Float.intBitsToFloat(0x7fc00000)}.
     */
    public static final float NaN = 0.0f / 0.0f;

eg.

        Integer aa = 127, bb = 127;
        System.out.println(aa == bb); //true  
        aa = 128;
        bb = 128;
        System.out.println(aa == bb); //false  --因为128超出范围
        System.out.println(aa.equals(bb)); //true  

        Integer a = 10; //this is autoboxing
        Integer b = Integer.valueOf(10); //under the hood
        System.out.println(a == b); // true

        Float c = 0f / 0f;
        Float d = 0f;

        System.out.println(c == d); // false -- c是NaN
        System.out.println(c.isNaN()); // true
        System.out.println(d.isNaN()); // false

        Double e = 0d / 0d;
        Double f = 0d;

        System.out.println(e == f); // false -- e是NaN
        System.out.println(e.isNaN()); // true
        System.out.println(f.isNaN()); // false

Integer

在 Java 5 中,为 Integer 的操作引入了一个新的特性,用来节省内存和提高性能。整型对象在内部实现中通过使用相同的对象引用实现了缓存和重用。上面的规则适用于整数区间 -128 到 +127
这种 Integer 缓存策略仅在自动装箱(autoboxing)的时候有用,使用构造器创建的 Integer 对象不能被缓存。
Java 编译器把原始类型自动转换为封装类的过程称为自动装箱(autoboxing),这相当于调用 valueOf 方法!

Integer a = 10; //this is autoboxing
Integer b = Integer.valueOf(10); //under the hood

源码如下:

在-128到127区间将取缓存中的,超出范围后会new新的地址堆对象。

    /**
     * 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);
    }

IntegerCache

 Integer 类中一个私有的静态类。

Javadoc 详细的说明这个类是用来实现缓存支持,并支持 -128 到 127 之间的自动装箱过程。最大值 127 可以通过 JVM 的启动参数 -XX:AutoBoxCacheMax=size 修改。 缓存通过一个 for 循环实现。从小到大的创建尽可能多的整数并存储在一个名为 cache 的整数数组中。这个缓存会在 Integer 类第一次被使用的时候被初始化出来。以后,就可以使用缓存中包含的实例对象,而不是创建一个新的实例(在自动装箱的情况下)。

实际上在 Java 5 中引入这个特性的时候,范围是固定的 -128 至 +127。后来在 Java 6 中,最大值映射到 java.lang.Integer.IntegerCache.high,可以使用 JVM 的启动参数设置最大值。这使我们可以根据应用程序的实际情况灵活地调整来提高性能。是什么原因选择这个 -128 到 127 这个范围呢?因为这个范围的整数值是使用最广泛的。 在程序中第一次使用 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 {@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 {
            // 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(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() {}
    }

缓存

Byte,Short,Long、Integer的缓存有固定范围: -128 到 127,对于 Character缓存范围是 0 到 127除了 Integer 可以通过参数改变范围外,其它的都不行

tip1: 
    String  valueOf方法只有对boolean的处理返回字面量(字符串常量池), 其他都是new新的!

    public static String valueOf(boolean b) {
        return b ? "true" : "false";
    }

tip2: 对于Byte而言值的范围在[-128,127] 

byte占一个字节空间,最高位是符号位,剩余7位能表示0-127,加上符号位的正负,就是-127至+127,但负0没必要,为充分利用,就用负零表示-128(即原码1000,0000)。(计算机转补码后存储)

对于boolean类型: 提供静态的2中枚举值

    public static Boolean valueOf(boolean b) {
        return (b ? TRUE : FALSE);
    }

ByteCache 缓存 Byte 、ShortCache 缓存 Short 、 LongCache 缓存 Long <三者源码类似,>

    private static class LongCache {
        private LongCache(){}

        static final Long cache[] = new Long[-(-128) + 127 + 1];

        static {
            for(int i = 0; i < cache.length; i++)
                cache[i] = new Long(i - 128);
        }
    }

CharacterCache 缓存 Character

    private static class CharacterCache {
        private CharacterCache(){}

        static final Character cache[] = new Character[127 + 1];

        static {
            for (int i = 0; i < cache.length; i++)
                cache[i] = new Character((char)i);
        }
    }
 
测试:
    public static void main(String[] args) {
        Long a = 3L;
        Integer b = 4;
        Character c = 5;
        Byte d = 7;
        Short e = 1;
        System.out.println(a == Long.valueOf(a));
        System.out.println(b == Integer.valueOf(b));
        System.out.println(c == Character.valueOf(c));
        System.out.println(d == Byte.valueOf(d));
        System.out.println(e == Short.valueOf(e));
    }

运行的结果都为true!

在断点单测时发现都跳入了valueOf方法!

转载于:https://my.oschina.net/u/3434392/blog/3009210

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值