基本类型与包装类

要明白装箱拆箱,首先要分清 Java 中的两种数据类型:

表格

基本数据类型 对应的包装类(引用类型)
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean
  • 基本类型:是简单值类型,存储在栈中,不能调用方法
  • 包装类:是类(引用类型),存储在堆中,可以调用方法

以 int 与 Integer 为例子,在64位系统下,int 只占用 4 字节的空间,而 Integer 在开启指针压缩的情况下还要占用16字节的空间。无论是读写效率还是存储效率,基本类型的效率都比包装类的效率高。

自动装箱与拆箱

自动装箱(Autoboxing)

自动将基本数据类型转换为对应的包装类对象的过程,由 Java 编译器自动完成,无需手动调用构造方法。

// 手动装箱(传统方式)
Integer num1 = new Integer(10);
// 自动装箱(编译器自动转换,等价于 Integer.valueOf(10))
Integer num2 = 10; 

自动拆箱(Unboxing)

自动将包装类对象转换为对应的基本数据类型的过程,同样由编译器自动完成。

Integer num3 = 20;
// 手动拆箱(传统方式)
int num4 = num3.intValue();
// 自动拆箱(编译器自动转换,等价于 num3.intValue())
int num5 = num3; 

实际应用场景

自动装箱 / 拆箱最常用在以下场景,也是新手最容易接触到的场景:

        集合操作

集合只能存储对象,不能直接存储基本数据类型,自动装箱 / 拆箱让操作更简洁:

import java.util.ArrayList;
import java.util.List;

public class BoxDemo {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        // 自动装箱:int → Integer
        list.add(10); 
        list.add(20);
        
        // 自动拆箱:Integer → int
        int firstNum = list.get(0); 
        System.out.println(firstNum); // 输出:10
    }
}

        方法参数 / 返回值

当方法的参数 / 返回值是包装类,但传入 / 接收的是基本类型时,自动转换:

public class BoxDemo2 {
    // 方法参数是包装类Integer
    public static void printNum(Integer num) {
        System.out.println(num);
    }
    
    // 方法返回值是包装类Integer
    public static Integer getNum() {
        // 自动装箱:int → Integer
        return 30; 
    }
    
    public static void main(String[] args) {
        // 自动装箱:int → Integer(传入基本类型10,自动转为Integer)
        printNum(10); 
        // 自动拆箱:Integer → int(接收包装类返回值,自动转为int)
        int result = getNum(); 
        System.out.println(result); // 输出:30
    }
}

        运算场景

包装类对象参与算术运算时,会先自动拆箱为基本类型,再计算:

public class BoxDemo3 {
    public static void main(String[] args) {
        Integer a = 5;
        Integer b = 10;
        // 自动拆箱:a和b先转为int,再相加;结果自动装箱为Integer
        Integer sum = a + b; 
        // 自动拆箱:sum转为int,再输出
        System.out.println(sum); // 输出:15
    }
}

注意事项

空指针异常

Map<Character, Character> map = new HashMap<>();
        char a = 'A';
        if(a == map.get('A')){
            System.out.println("true");
        }else{
            System.out.println("false");
        }

上述代码会报空指针异常,但如果把 a 的类型改为 Character包装类,则能正确运行。

本质是因为map中没有存储 ‘A’ 的键值对,因此返回的是空对象。又因为我们是用基础类型来和其比较,系统会尝试将空对象进行拆箱,因此报出空指针异常。所以要把 a 转为包装类型,避免空指针异常。

缓存池问题

Integer有缓存池(默认 - 128~127),这个范围内的自动装箱会复用对象,超出范围则新建对象:

Integer a = 127;
Integer b = 127;
System.out.println(a == b); // true(复用缓存对象)

Integer c = 128;
Integer d = 128;
System.out.println(c == d); // false(新建对象,==比较地址)
System.out.println(c.equals(d)); // true(equals比较值,推荐用equals)

性能影响

频繁的装箱 / 拆箱会产生额外的对象,增加 GC 压力,高性能场景(如循环运算)建议直接用基本类型。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐