自动装箱和自动拆箱(慎用“==”)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Carrots_vegetables/article/details/83019484

先来看一段非常“简单”的代码

public static void main(String[] args) {
		Integer i1 = 100, i2 = 100, i3 = 130, i4 = 130;
		System.out.println(i1 == i2);
		System.out.println(i3 == i4);
	}

如果你觉得输出的是两个ture,哪我觉得你还需要再学习一下Inreger的源码(虽然一开始是我也是这样的)。

实际 输出结果是这样的

true
false

为什么会出现这样的结果呢?我们可以看到上面的代码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() {}//私有构造
    }

这样问题就一目了然;因为i3、i4的值是130已经 超过了127所以一进行自动装箱结果自然是false。

总结:

简单一点说,装箱就是 自动将基本数据类型转换为包装器类型;拆箱就是 自动将包装器类型转换为基本数据类型。
下表是基本数据类型对应的包装器类型:

int(4字节)	Integer
byte(1字节)	Byte
short(2字节)	Short
long(8字节)	Long
float(4字节)	Float
double(8字节)	Double
char(2字节)	Character
boolean(未定)	Boolean

他们都会都会存在类似的问题,具体原因自己去看源码。

扩展一个非常基础的问题(java中==和equals的区别)

java中的数据类型,可分为两类:

1.基本数据类型,也称原始数据类型。byte,short,char,int,long,float,double,boolean
他们之间的比较,应用双等号(),比较的是他们的值。
2.复合数据类型(类)
当他们用(
)进行比较的时候,比较的是他们在内存中的存放地址,所以,除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false。 JAVA当中所有的类都是继承于Object这个基类的,在Object中的基类中定义了一个equals的方法,这个方法的初始行为是比较对象的内存地 址,但在一些类库当中这个方法被覆盖掉了,如String,Integer,Date在这些类当中equals有其自身的实现,而不再是比较类在堆内存中的存放地址了。
对于复合数据类型之间进行equals比较,在没有覆写equals方法的情况下,他们之间的比较还是基于他们在内存中的存放位置的地址值的,因为Object的equals方法也是用双等号()进行比较的,所以比较后的结果跟双等号()的结果相同。

小问题大bug

public static void main(String[] args) {
		int i1=100;
		int i2=200;
		Integer a=i1;
		Integer b=i1;
		Integer c=i2;
		Integer d=i2;
		if(a==b) {
			System.out.println("成功执行");
		}
		
		if(c==d) {
			System.out.println("能成功执行吗");
		}
	}

如果在平常的项目中出现像上面一样的逻辑判断最后出现的bug我觉得是非常难找出来的。。。。。。

猜你喜欢

转载自blog.csdn.net/Carrots_vegetables/article/details/83019484