JVM学习笔记--语法糖之 自动装箱的陷阱

 

JVM的自动装箱、自动拆箱语法糖看起来虽然简单,但也不见得就没有任何值得我们注意的地方,下面代码演示了自动装箱的一些错误用法:

public class SyntaxSugarTest {
	public static void main(String[] args) {
		Integer a = 1;
		Integer b = 2;
		Integer c = 3;
		Integer d = 3;
		Integer e = 128;
		Integer f = 128;
		Long g = 3L;
		System.out.println("c == d : " + (c == d));
		System.out.println("e == f : " + (e == f));
		System.out.println("c == (a + b) : " + (c == (a + b)));
		System.out.println("c.equals(a + b) : " + (c.equals(a + b)));		
		System.out.println("g == (a + b) : " + (g == (a + b)));
		System.out.println("g.equals(a + b) : " + (g.equals(a + b)));		
	}
}


上面代码的运行结果如下:

c == d : true
e == f : false
c == (a + b) : true
c.equals(a + b) : true
g == (a + b) : true
g.equals(a + b) : false

这个结果也许出乎部分人的意料,这就是JVM自动装箱、自动拆箱语法糖在捣鬼。我们把上面的代码编译后的.class文件进行反编译,反编译后的源代码文件中的语法糖已经被擦除,详细如下:

public class SyntaxSugarTest
{
  public static void main(String[] args)
  {
    Integer a = Integer.valueOf(1);
    Integer b = Integer.valueOf(2);
    Integer c = Integer.valueOf(3);
    Integer d = Integer.valueOf(3);
    Integer e = Integer.valueOf(128);
    Integer f = Integer.valueOf(128);
    Long g = Long.valueOf(3L);
    System.out.println("c == d : " + (c == d));
    System.out.println("e == f : " + (e == f));
    System.out.println("c == (a + b) : " + (c.intValue() == a.intValue() + b.intValue()));
    System.out.println("c.equals(a + b) : " + c.equals(Integer.valueOf(a.intValue() + b.intValue())));
    System.out.println("g == (a + b) : " + (g.longValue() == a.intValue() + b.intValue()));
    System.out.println("g.equals(a + b) : " + g.equals(Integer.valueOf(a.intValue() + b.intValue())));
  }
}

从上面的反编译后的代码可以看出:包装类(如Integer类)的 “==”运算在没有遇到算术运算的情况下不会自动拆箱,且它们的equals()方法不会处理数据类型转换的关系。如:

System.out.println("c == d : " + (c == d));//没有算术运算符,不会自动拆箱,因此仍然是对象之间的比较
System.out.println("e == f : " + (e == f));//原理同上,至于结果为何不同见下面分析
System.out.println("c == (a + b) : " + (c.intValue() == a.intValue() + b.intValue()));//有+运算,会自动拆箱,因此变为原子类型的普通数值比较
System.out.println("g.equals(a + b) : " + g.equals(Integer.valueOf(a.intValue() + b.intValue())));//不会自动处理类型转换

也许有人会问,同样是没有自动拆箱,同样是对象之间的比较,且数值一样,为何c 与d,e与f之间的比较结果会不同呢?且看下面分析:

1.我们知道在JAVA中用“==”进行对象之间的比较时,如果两对象都指向同一个引用(内存空间地址),那么返回true,否则返回false。

2.我们来看看Integer.valueOf()方法的源码及说明:

    /**
     * Returns a <tt>Integer</tt> instance representing the specified
     * <tt>int</tt> value.
     * If a new <tt>Integer</tt> 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.
     * ========下文中的IntegerCache.high = 127(默认) high value may be configured by property
     * @param  i an <code>int</code> value.
     * @return a <tt>Integer</tt> instance representing <tt>i</tt>.
     * @since  1.5
     */
    public static Integer valueOf(int i) {
        if(i >= -128 && i <= IntegerCache.high) 
            return IntegerCache.cache[i + 128];
        else
            return new Integer(i);
    }
//上文中的IntegerCache.high = 127(默认) high value may be configured by property

结合1、2的说明,相信大家就明白为何是这种结果了。

综上所述,我们在实际编码过程中应该尽量避免这样来使用自动装箱与自动拆箱 语法糖。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值