zoukankan      html  css  js  c++  java
  • Java自动装箱与缓存

    自动装箱与缓存


    现象

    有以下代码:

     1 public class Main {
     2    public static void main(String[] args) {
     3        Integer i1 = 127;
     4        Integer i2 = 127;
     5        Integer i3 = new Integer(127);
     6        Integer i4 = new Integer(127);
     7
     8         System.out.println(i1 == i2);//true
     9         System.out.println(i3 == i4);//false
    10     }
    11 }
    
    控制台输出:
        true
        false,
    

    我们知道,第3、4行发生了自动装箱,生成了Integer对象,并将对象的引用赋值给i1和i2,“==”比较的是对象的引用,控制台输出看,i1和i2保存了同一个Integer对象的引用。

    下面对上述代码进行反编译:

    /*
     * Decompiled with CFR 0.149.
     */
    package com.learn.java;
    
    public class Main {
        public static void main(String[] args) {
            Integer i1 = Integer.valueOf((int)127);
            Integer i2 = Integer.valueOf((int)127);
            Integer i3 = new Integer((int)127);
            Integer i4 = new Integer((int)127);
            System.out.println((i1 == i2 ? 1 : 0) != 0);
            System.out.println((i3 == i4 ? 1 : 0) != 0);
        }
    }
    

    从反编译结果看,Integer类自动装箱执行了valueOf方法。


    本质

    下面是Integer类中构造方法和ValueOf(int)方法的源码以及注释:

    package java.lang;
    import java.lang.annotation.Native;
    public final class Integer extends Number implements Comparable<Integer> {
       /**
         * Constructs a newly allocated Integer object that represents the specified int value.
         * 创建一个新的、包装了指定int数值的Integer实例。
         * @params value - the value to be represented by the Integer object.
         */
        public Integer(int value) {
            this.value = value;
        }
        
        /**
         * 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实例。除非必须返回一个Integer实例,应该优先使用valueOf(int)方法而
         * 不是Integer(int)方法。valueOf(int)方法通过事先缓存常用的数值,表现出更好的时间、空间性能。
         * 
         * This method will always cache values in the range -128 to 127,inclusive, and may cache other 
         * values outside of this range.
         * 默认情况下,缓存-128~127范围内的值,缓存范围可根据需要进行一定的调整。
         *
         * @param  i - an int value.
         * @return an 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);
        }
    }
    

    下面是valueOf(int)方法中使用到的IntegerCache内部类的源码:

        /**
         * 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.
         * 缓存在首次使用时完成初始化,缓存的范围(上界)可通过 -XX:AutoBoxCacheMax 配置。
         */
        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);
                        // 127是缓存的最小上界
                        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() {}
        }
    

    上面源码中的信息可以总结为以下几点:

    1. valueOf(int)方法不一定返回新Integer实例的引用。如果int数值在缓存范围内,返回的是缓存中已经存在的Integer实例的引用,这意味着,在不同的地方,使用相同的int数值调用valueOf(int)方法,可能得到相同的引用。
    2. 缓存在第一次使用valueOf(int)方法时创建。所以第一次使用valueOf(int)方法需要消耗额外的时间。
    3. 默认情况下,缓存数值在-128~127范围内的实例。
    4. 可以使用参数调整缓存的上界。最大上界为Integer.MAX_VALUE,最小上界为127(默认为该值)
    5. 最多缓存Integer.MAX_VALUE个元素。

    拓展

    下面看看其他包装类有没有与Integer类一样的缓存机制。

    1. Byte

    public final class Byte extends Number implements Comparable<Byte> {
    
        public static Byte valueOf(byte b) {
            final int offset = 128;
            return ByteCache.cache[(int)b + offset];
        }
    
        private static class ByteCache {
            private ByteCache(){}
    
            static final Byte cache[] = new Byte[-(-128) + 127 + 1];
    
            static {
                for(int i = 0; i < cache.length; i++)
                    cache[i] = new Byte((byte)(i - 128));
            }
        }
    }
    

    从源码看,Byte也有类似的缓存机制,但是缓存的范围是固定的。

    2. Short

    public final class Short extends Number implements Comparable<Short> {
           
        public static Short valueOf(short s) {
            final int offset = 128;
            int sAsInt = s;
            if (sAsInt >= -128 && sAsInt <= 127) { // must cache
                return ShortCache.cache[sAsInt + offset];
            }
            return new Short(s);
        }
        
        private static class ShortCache {
            private ShortCache(){}
    
            static final Short cache[] = new Short[-(-128) + 127 + 1];
    
            static {
                for(int i = 0; i < cache.length; i++)
                    cache[i] = new Short((short)(i - 128));
            }
        }
    }
    

    从源码看,Short也有类似的缓存机制,但是缓存的范围是固定的。

    3. Long

    public final class Long extends Number implements Comparable<Long> {
        
        public static Long valueOf(long l) {
            final int offset = 128;
            if (l >= -128 && l <= 127) { // will cache
                return LongCache.cache[(int)l + offset];
            }
            return new Long(l);
        }
        
        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);
            }
        }
    }
    

    从源码看,Long也有类似的缓存机制,但是缓存的范围是固定的。

    4. Float

    public final class Float extends Number implements Comparable<Float> {
        public static Float valueOf(float f) {
            return new Float(f);
        }
    }
    

    从源码看,Float没有缓存机制。

    5. Double

    public final class Double extends Number implements Comparable<Double> {
    	public static Double valueOf(double d) {
       	 	return new Double(d);
    	}
    }
    

    从源码看,Double没有缓存机制。

  • 相关阅读:
    软件工程14—第09组 Beta冲刺(2/4)
    软件工程13—第09组 Beta冲刺(1/4)
    软件工程12—第09组 Alpha事后诸葛
    软件工程11—第09组 Alpha冲刺(4/4)
    软件工程10—第09组 Alpha冲刺(3/4)
    软件工程09—第09组 Alpha冲刺(2/4)
    软件工程08—第09组 Alpha冲刺(1/4)
    软件工程07—第09组 团队Git现场编程实战
    软件工程06—亚瑟王の十三水2.0
    第06组 Alpha冲刺(4/6)
  • 原文地址:https://www.cnblogs.com/XiaoZhengYu/p/12822707.html
Copyright © 2011-2022 走看看