在Java中一共定义了8种基础数据类型。为了满足在特殊情况能够使用对象而非基本数据类型的方式来操作数值,Java中还定义了与基础数据类型一一对应的包装类。
所有的包装类都继承自java.lang.Number这个抽象类。
基本类型 | 包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
boolean | Boolea |
char | Character |
自动装箱与拆箱
- 自动装箱:指的是基本数据类型自动转换为对应的包装类
- 自动拆箱:指的是包装类自动转换为对应的基本数据类型
自动拆箱、装箱是JDK1.5之后引入的特性,这让我们能够用基本数据类型的定义操作方式来定义操作包装类。比如:
Integer num = 100;
Integer num2 = 1;
int num3 = num + num2;
System.out.println(num3);
输出结果:101
🤔自动装箱、拆箱是如何实现的?
为了搞明白Java是如何实现自动装箱和拆箱的,让我们来反编译.class文件,执行如下命令:
javap -c IntegerTest.class
反编译后的内容如下:
Compiled from "IntegerTest.java"
public class org.zhangyaqi.java.IntegerTest {
public org.zhangyaqi.java.IntegerTest();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: bipush 100
2: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: astore_1
6: iconst_1
7: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
10: astore_2
11: aload_1
12: invokevirtual #3 // Method java/lang/Integer.intValue:()I
15: aload_2
16: invokevirtual #3 // Method java/lang/Integer.intValue:()I
19: iadd
20: istore_3
21: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
24: iload_3
25: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
28: return
}
通过反编译.class文件我们发现,java在编译过程中将我们代码中对Integer的操作做了自动转换,分别调用了valueOf(int)和intValue()方法从而实现自动装箱与拆箱(反编译代码中2、7、12、16对应的注释),转换操作如下:
Integer num = 100; 转换为
Integer num = Integer.valueOf(100)
Integer num2 = 1; 转换为
Integer num2 = Integer.valueOf(1)
int num3 = num + num2; 转换为
int num3 = num.intValue() + num2.intValue();
🤔操作包装类需要注意什么呢?
自动装箱、拆箱的特性让我们在开发过程中极大的方便开发人员的对包装类的使用,但是同样也是因为这个特性的存在,实际使用如果不注意经常会遇到以下问题:
- 调用方法要求参数为int类型,结果传入的是Integer类型,由于自动拆箱的特性,如果传入Integer对象为null,将触发空指针异常
- 调用方法要求参数为Integer类型,结果传入的是int类型,由于自动装箱的存在,最终传入的Integer对象将无论如何都不会是null,如果在方法中对Integer为null有特殊的逻辑处理,那么该逻辑则永远不会触发
- 在对两个包装类对象进行是否相等的判断时,不能使用"=="而要调用equals(Object) 方法,具体原因会在之后的文章中详细说明
网友评论