Java中的装箱与拆箱(转)_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > Java中的装箱与拆箱(转)

Java中的装箱与拆箱(转)

 2011/9/19 20:59:59  ruoyi  http://ruoyi.iteye.com  我要评论(0)
  • 摘要:在J2SE5.0后推出了自动装箱和拆箱的功能,以提高我们的开发效率,然而自动装箱和拆箱实际上是通过编译器来支持的(并非语言本身,或者说虚拟机),因而这种支持也隐藏了部分内部实质,再加上某些类的优化(比如Integer里面的缓存等,参看关于缓存节),就更加容易在特定的环境下产生问题,并且如果不知道原来还无法调试。以下先是简单的介绍了编译器对装箱和拆箱的实现,并根据实现简单介绍一下可能会遇到的几个问题。装箱和拆箱实现以下装箱和拆箱代码:Objectvalue=10;intintValue=
  • 标签:Java

J2SE5.0 后推出了自动装箱和拆箱的功能,以提高我们的开发效率,然而自动装箱和拆箱实际上是通过编译器来支持的(并非语言本身,或者说虚拟机),因而这种支持也隐藏了部分内部实质,再加上某些类的优化(比如 Integer 里面的缓存等,参看关于缓存 节),就更加容易在特定的环境下产生问题,并且如果不知道原来还无法调试。以下先是简单的介绍了编译器对装箱和拆箱的实现,并根据实现简单介绍一下可能会遇到的几个问题。

装箱和拆箱实现

以下装箱和拆箱代码:

?? ? ? Object?value? = ? 10 ;
???????
int ?intValue? = ?(Integer)value;
???????Integer?newIntValue?
= ? new ?Integer( 10 );

?

编译成字节码如下:

???? 0?bipush 10

?? ??2?invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [20]

???? 5?astore_1 [value]

???? 6?aload_1 [value]

???? 7?checkcast java.lang.Integer [21]

??? 10?invokevirtual java.lang.Integer.intValue() : int [26]

??? 13?istore_2 [intValue]

??? 14?new java.lang.Integer [21]

?? ?17?dup

??? 18?bipush 10

??? 20?invokespecial java.lang.Integer(int) [30]

??? 23?astore_3 [newIntValue]

从以上字节码可以看到 10 首先调用 valueOf 方法转换为 Integer 实例,再赋值该 value ,而 value 强制转换成 Integer 类后,会调用 intValue 方法,后赋值给 intValue 。这就是用编译器来实现装箱和拆箱。

?

奇怪的 NullPointerException

查看以下代码:

?? ? ? Integer?value? = ? null ;
???????
int ?intValue? = ?value;

?

可以编译通过,但是运行的时候却会发生 NullPointerException 。这是由什么引起的呢?依然看一下字节码就可以了:

???? 0?aconst_null

???? 1?astore_1 [value]

???? 2?aload_1 [value]

????3?invokevirtual java.lang.Integer.intValue() : int [20]

???? 6?istore_2 [intValue]

从字节码中可以看到,从 value 赋值该 intValue 事实上是直接在 value 实例上调用 intValue 函数。

对当前代码,我们可以一眼就看出当前 value null 的问题,但是如果这个 null 是在很远以外的地方赋值的呢?或者是间接赋值呢?这个时候遇到这种问题就会比较诡异了。

?

相等与不相等问题

查看一下代码:

?? ? ? Integer?value1? = ? 100 ;
???????Integer?value2?
= ? 100 ;
???????System.out.println(
" value1?==?value2?is? " ? + ?(value1? == ?value2));
??????
???????Integer?value3?
= ? 200 ;
???????Integer?value4?
= ? 200 ;
???????System.out.println(
" value3?==?value4?is? " ? + ?(value3? == ?value4));

?

这段代码会是什么结果?

value1 == value2 is true

value3 == value4 is false

?

两段代码就是值不一样,其他的都一样,竟然会有区别?这个奥妙就因为装箱过程中调用的是 valueOf 方法,而 valueOf 方法对值在 -128 127 之间的数值缓存了(参见关于缓存一节),因而 value1 value2 的引用是相同的,而 value3 value4 的引用是不一样的,而 == 比较的是引用,因而才会出现以上的结果。

这确的做法应该是:

?? ? ? Integer?value1? = ? 100 ;
???????Integer?value2?
= ? 100 ;
???????System.out.println(
" value1?==?value2?is? " ? + ?(value1.equals(value2)));
??????
???????Integer?value3?
= ? 200 ;
???????Integer?value4?
= ? 200 ;

?? ? ? System.out.println( " value3?==?value4?is? " ? + ?(value3.equals(value4))); ?

这样的结果就是预料的结果了:

value1 == value2 is true

value3 == value4 is true

?

所以我们要慎用“ == caozuofu.html" target="_blank">操作符。

?

String中的相等与不等

String 中也有类似的情况,查看一下代码:

?? ? ? String?str1? = ? " abc " ;
???????String?str2?
= ? " abc " ;
???????System.out.println(
" str1?==?str2?is? " ? + ?(str1? == ?str2));
??????
???????String?str3?
= ? new ?String( " abc " );
???????String?str4?
= ? new ?String( " abc " );
???????System.out.println(
" str3?==?str4?is? " ? + ?(str3? == ?str4));

?

执行结果:

str1 == str2 is true

str3 == str4 is false

?

这是因为 str1 str2 使用的是同一个字符串,即在字符常量中的字符串,而 str3 str4 在使用字符常量中的字符为参数又创建出了两个新的字符串对象,因而在引用比较情况下是不等的。我们可以从字节码中得到这些信息(删除打印的代码):

?? ??0?ldc <String "abc"> [20]

???? 2?astore_1 [str1 ]

???? 3?ldc <String "abc"> [20]

???? 5?astore_2 [str2]

???? 6?new java.lang.String [22]

???? 9?dup

??? 10?ldc <String "abc"> [20]

??? 12?invokespecial java.lang.String(java.lang.String) [24]

??? 15?astore_3 [str3 ]

??? 16?new java.lang.String [22]

??? 19?dup

?? ?20?ldc <String "abc"> [20]

??? 22?invokespecial java.lang.String(java.lang.String) [24]

??? 25?astore 4 [str4]

正确的做法还是调用 equals 方法,而不是使用“ == ”操作符。

?

关于缓存

据目前信息,有缓存的类有: Byte Short Integer Long 以及 Boolean 类。而这种缓存也只是在调用 valueOf (静态)方法的时候才会存在(装箱正是调用了 valueOf 方法)。对整型,缓存的值都是 -128 127 (包括 -128 127 )之间,其他值都不缓存,而对 Boolean 类型只有 true false 值。代码如下:

public ? final ? class ?Integer? extends ?Number?{
????
public ? static ?Integer?valueOf( int ?i)?{
????????
if (i? >= ? - 128 ? && ?i? <= ?IntegerCache.high)
????????????
return ?IntegerCache.cache[i? + ? 128 ];
????????
else
????????
return ? new ?Integer(i);
}
public ? final ? class ?Boolean?{
????
public ? static ?Boolean?valueOf( boolean ?b)?{
????????
return ?(b? ? ?TRUE?:?FALSE);
????}


发表评论
用户名: 匿名