在
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
所以我们要慎用“
==
”操作符。
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);
}
分享到:
相关推荐
自动装箱和拆箱是Java语言中的重要特性,它们简化了基本数据类型与包装类之间的转换过程。然而,这两个机制也带来了一定的性能影响。为了编写更高效、更可维护的Java代码,开发者需要了解自动装箱和拆箱的工作原理、...
在Java编程语言中,自动装箱(Autoboxing)和自动拆箱(Unboxing)是两个重要的特性,它们简化了基本类型(如int、double等)与对应的包装类(如Integer、Double等)之间的转换过程。这些特性是在Java 5引入的,极大...
Java中的装箱和拆箱是面向对象编程中的一个重要概念,主要涉及到Java的自动类型转换机制。装箱是指将基本数据类型(如int、char、boolean等)转换为对应的包装器类对象,而拆箱则是相反的过程,即把包装器类的对象...
在Java编程语言中,自动装箱(Autoboxing)和自动拆箱(Unboxing)是从Java 1.5版本开始引入的一项特性,其目的是简化原始类型(Primitive Types)与它们对应的包装类(Wrapper Classes)之间的转换过程。...
本文将深入讲解Java装箱与拆箱的基本概念,并通过实例代码进行演示。 装箱(Boxing)是Java自动将基本数据类型转换为对应的包装类的过程。例如,int类型转换为Integer,char类型转换为Character等。这是Java 5引入...
自动装箱与拆箱的实现原理 自动装箱是指Java将原始类型值转换成对应的对象的过程,如将int类型的变量转换成Integer对象。反之,将对象转换成原始类型值的过程称为拆箱。因为这里的装箱和拆箱是自动进行的非人为转换...
### Java中的自动装箱与拆箱详解 #### 引言 在Java开发过程中,开发者经常需要处理各种数据类型之间的转换。对于基本数据类型与包装类之间的转换,Java提供了一个非常便利的功能——自动装箱和自动拆箱。这些功能...
Java中自动装箱、拆箱引起的耗时详解 Java中自动装箱和拆箱是Java语言中一个重要的特性,它可以将基本数据类型和它们的包装类之间进行转换,这个过程是透明的,程序员不需要手动进行转换。但是,这个过程会引起一些...
### Java中的自动装箱与拆箱 #### 一、概念介绍 在Java中,自动装箱(Autoboxing)和拆箱(Unboxing)是Java编译器提供的一种特性,用于在基本数据类型和对应的包装类之间进行自动转换。这种特性简化了编程过程中...
自动装箱和拆箱从Java 1.5开始引入,目的是将原始类型值转自动地转换成对应的对象。自动装箱与拆箱的机制可以让我们在Java的变量赋值或者是方法调用等情况下使用原始类型或者对象类型更加简单直接。 如果你在Java...
“深入理解Java中的装箱和拆箱” 一、什么是装箱?什么是拆箱? 在Java中,每种基本数据类型都有对应的包装器类型,例如int对应Integer、byte对应Byte等。装箱是指将基本数据类型自动转换为包装器类型的过程,而...
java装箱拆箱.ppt java装箱拆箱.ppt
本文先讲述装箱和拆箱基本的东西,再来看一下面试笔试中经常遇到的与装箱、拆箱相关的问题。 以下是本文的目录大纲: 一.什么是装箱?什么是拆箱? 二.装箱和拆箱是如何实现的 三.面试中相关的问题 ...
拆箱与装箱相反,指的是将包装类对象转换回基本数据类型的过程。同样地,在Java SE 5.0及以后版本中,也支持自动拆箱的功能。 **示例代码**: ```java Integer i = 10; int j = i; // 自动拆箱 ``` 这段代码中,...
Java中的自动装箱和拆箱是自J2SE 5.0版本引入的特性,它极大地简化了基本数据类型与其对应的包装类之间的转换过程。基本数据类型包括int、double、boolean等,而包装类如Integer、Double和Boolean分别对应这些基本...
Java中的自动装箱和拆箱是自JDK 1.5版本引入的一种语言特性,它极大地简化了基础数据类型(如int)与它们对应的包装类(如Integer)之间的转换过程。这一特性使得开发者无需手动创建包装类实例或使用显式类型转换,...
在 Java 5 中引入了自动装箱与拆箱的功能,使得开发者在使用基本类型和它们对应的包装类之间更加灵活。 **示例**: ```java // 自动装箱 int num = 10; Integer numObj = num; // numObj 是 Integer 对象 // 自动...
Java中的装箱和拆箱是面向对象编程中的一个重要概念,主要涉及到基本数据类型与它们对应的包装器类之间的转换。在Java SE 5及以后的版本中,为了方便开发者使用,引入了自动装箱和拆箱的功能。 一、什么是装箱和...
Java面试题06.装箱和拆箱.mp4
自动装箱与拆箱:自动装箱(Autoboxing)指的是自动地将基本数据类型转换为对应的包装类对象;自动拆箱(Unboxing)则是将包装类对象自动转换为基本数据类型。 常用方法:演示如何使用包装类中的这些常见方法。 null...