您的位置:首页 > 其它

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

2011-11-27 13:52 246 查看
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的说明,相信大家就明白为何是这种结果了。

综上所述,我们在实际编码过程中应该尽量避免这样来使用自动装箱与自动拆箱 语法糖。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: