在Java编程中,我们经常需要在基本数据类型和对应的包装类之间做转换,这就涉及到了装箱、拆箱以及自动装箱的概念。下面我们先通过一张图了解基本数据类型和包装类的对应关系,再逐步展开讲解。

基本数据类型与包装类的关系
Java有8种基本数据类型,每种基本数据类型都有对应的包装类,它们的关系如下:
| 基本数据类型 | 包装类 |
|---|---|
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| float | Float |
| double | Double |
| char | Character |
| boolean | Boolean |
什么是装箱和拆箱
装箱
装箱指的是把基本数据类型转换为对应的包装类对象的过程。在Java中,我们可以通过包装类的构造方法或者valueOf()方法完成装箱操作。
下面是一个手动装箱的示例代码:
public class BoxDemo {
public static void main(String[] args) {
// 基本数据类型int
int num = 10;
// 手动装箱,使用Integer的构造方法
Integer boxedNum1 = new Integer(num);
// 手动装箱,使用Integer的valueOf方法
Integer boxedNum2 = Integer.valueOf(num);
System.out.println("装箱后的对象值:" + boxedNum1 + "," + boxedNum2);
}
}拆箱
拆箱和装箱相反,指的是把包装类对象转换为对应的基本数据类型的过程,我们可以通过包装类的xxxValue()方法完成拆箱操作。
下面是一个手动拆箱的示例代码:
public class UnboxDemo {
public static void main(String[] args) {
// 包装类对象Integer
Integer boxedNum = Integer.valueOf(20);
// 手动拆箱,使用intValue方法
int num = boxedNum.intValue();
System.out.println("拆箱后的基本类型值:" + num);
}
}什么是自动装箱和自动拆箱
从Java 5开始,编译器会自动帮我们完成装箱和拆箱的操作,不需要我们手动调用构造方法或者valueOf()、xxxValue()方法,这个过程就叫做自动装箱和自动拆箱。
我们来看一段自动装箱和自动拆箱的代码:
public class AutoBoxDemo {
public static void main(String[] args) {
// 自动装箱:编译器自动把int转换为Integer
Integer autoBoxed = 30;
// 自动拆箱:编译器自动把Integer转换为int
int autoUnboxed = autoBoxed;
System.out.println("自动装箱后的值:" + autoBoxed);
System.out.println("自动拆箱后的值:" + autoUnboxed);
// 自动装箱和拆箱在运算中的体现
Integer a = 10; // 自动装箱
Integer b = 20; // 自动装箱
int sum = a + b; // a和b先自动拆箱为int,再做加法,结果赋值给sum是基本类型
Integer result = a + b; // 先拆箱做加法,再把结果自动装箱为Integer
System.out.println("a + b = " + sum + ",包装类结果:" + result);
}
}使用自动装箱拆箱的注意事项
包装类的缓存机制
部分包装类有缓存机制,比如Integer默认缓存了-128到127之间的对象,当我们通过valueOf()方法创建这个范围内的Integer对象时,会直接返回缓存中的对象,而不是新建对象。
我们来看一段验证缓存的代码:
public class CacheDemo {
public static void main(String[] args) {
// 自动装箱本质是调用Integer.valueOf()
Integer i1 = 100;
Integer i2 = 100;
// 100在缓存范围内,i1和i2指向同一个对象
System.out.println("i1 == i2(100):" + (i1 == i2)); // 输出true
Integer i3 = 200;
Integer i4 = 200;
// 200不在缓存范围内,i3和i4是新创建的不同对象
System.out.println("i3 == i4(200):" + (i3 == i4)); // 输出false
}
}需要注意的是,Byte、Short、Long、Character也有类似的缓存机制,Boolean直接缓存了TRUE和FALSE两个对象,而Float和Double没有缓存。
空指针风险
自动拆箱时,如果包装类对象是null,就会抛出NullPointerException,这一点在使用的时候要特别注意。
示例代码如下:
public class NullPointerDemo {
public static void main(String[] args) {
Integer nullInt = null;
try {
// 自动拆箱时,null无法转换为基本类型,会抛空指针
int num = nullInt;
System.out.println(num);
} catch (NullPointerException e) {
System.out.println("发生空指针异常:" + e.getMessage());
}
}
}性能影响
虽然自动装箱拆箱简化了代码,但频繁的装箱拆箱操作会产生额外的对象创建和销毁开销,如果是在循环等高频执行的场景中,可能会影响程序性能,这种情况下建议尽量使用基本数据类型。
总结来说,装箱是基本类型转包装类,拆箱是包装类转基本类型,自动装箱拆箱是编译器帮我们完成的简化操作,使用时要注意缓存范围和空指针问题,避免在性能敏感场景过度使用。