【Java SE】包装类(Wrapper Class)

包装类

在Java中,有一句广为流传的名言:"万物皆对象 "。然而,这句话其实并不完全准确。因为我们还有8个"异类"------intdoubleboolean等基本数据类型。它们不是对象,无法调用方法,也无法在集合中存储。

为了解决这个问题,包装类应运而生。它们就像给基本数据类型穿上了一件"对象的外衣"。

什么是包装类?

包装类是Java为每种基本数据类型提供的对应的引用类型。

基本类型 包装类
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

注意 :除了IntegerCharacter,其他包装类的名字与基本类型名首字母大写即可。

为什么需要包装类?

1. 泛型与集合的必需品

Java的泛型不支持基本类型。如果想创建一个ArrayList来存储整数,必须使用ArrayList<Integer>。如果试图写ArrayList<int>,编译器会直接报错。

2. 对象方法的调用

包装类提供了许多实用的静态方法,方便类型转换。

java 复制代码
// 将字符串转换为整数
int num = Integer.parseInt("123");
// 将整数转换为二进制字符串
String binary = Integer.toBinaryString(10); // 输出 "1010"

3.实体类(POJO)中使用包装类

在领域模型中,建议使用包装类。

  • 数据库的字段可能是NULL,映射到int会变成0,产生业务歧义。
  • 使用Integer可以完美区分"未设置"和"设置为0"。

装箱与拆箱⭐

  • 装箱:将基本类型转换为包装类对象。
  • 拆箱:将包装类对象转换为基本类型。

手动 装箱/拆箱

java 复制代码
int a = 10;
Integer num =Integer.valueOf(a); // 手动装箱
int b = num.intValue();          // 手动拆箱
double c=num.doubleValue();

自动 装箱/拆箱

java 复制代码
Integer num = 10;   // 自动装箱:相当于 Integer.valueOf(10)
int d = num;        // 自动拆箱:相当于 num.intValue()

valueOf() 源码分析(包装类缓存池) ⭐

这是包装类中最容易出错,也是面试中最常考的点:缓存池

我们来看一段代码:

java 复制代码
Integer a = 100;
Integer b = 100;
System.out.println(a == b); // 输出 true 还是 false?

Integer c = 200;
Integer d = 200;
System.out.println(c == d); // 输出 true 还是 false?

运行结果:

复制代码
true
false

为什么呢?ctrl+B看看valueOf() 源码

cpp 复制代码
public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

使用自动装箱(Integer.valueOf())时,JVM为了提高性能和节省内存,会对特定范围内的数值进行缓存

  • IntegerCache.lowstatic final int low = -128
  • IntegerCache.highstatic final int high= 127
  • 代码逻辑
    • 如果i的值在[-128, 127]之间,valueOf()方法会直接从缓存数组中返回同一个Integer对象
    • 如果超出这个范围,则new一个新的Integer对象

在例子中,ab都指向缓存中的同一个对象,所以==比较内存地址返回true。而cd是两个不同的对象,返回false

注意==比较的是内存地址(引用),比较数值请使用equals()方法。
更多补充缓存池和常量池的区别

包装类在集合中的应用与性能考量

开销分析 ⭐

虽然包装类很方便,但在高频数据计算中,它带来了额外的性能开销。

java 复制代码
// 性能较差的写法
Integer sum = 0; // Integer sum = Integer.valueOf(0);
for (int i = 0; i < 10000; i++) {
    sum += i; 
    // sum = Integer.valueOf(sum.intValue() + i);
    // 这里每次循环都发生了:拆箱 -> 计算 -> 装箱
}

10000次循环会创建约10000个Integer对象(实际上因为缓存机制,0-127范围内的值可能复用,但整体数量依然很大)。这会增加GC(垃圾回收)的压力。在高性能场景下,优先使用基本类型int进行计算。

性能对比测试

java 复制代码
public class PerformanceTest {
    // 使用包装类
    public static void testWrapper() {
        long start = System.nanoTime();
        Integer sum = 0;
        for (int i = 0; i < 10000000; i++) {  // 1000万次
            sum += i;
        }
        long end = System.nanoTime();
        System.out.println("包装类耗时: " + (end - start) / 1000000 + " ms");
    }

    // 使用基本类型
    public static void testPrimitive() {
        long start = System.nanoTime();
        int sum = 0;
        for (int i = 0; i < 10000000; i++) {
            sum += i;
        }
        long end = System.nanoTime();
        System.out.println("基本类型耗时: " + (end - start) / 1000000 + " ms");
    }

    public static void main(String[] args) {
        testPrimitive();  // 输出: 基本类型耗时: 5 ms
        testWrapper();    // 输出: 包装类耗时:  43 ms

    }
}

null 拆箱引发的 NPE

自动拆箱时,如果包装类对象为null,会抛出NullPointerException

java 复制代码
Integer num = null;
int i = num; // 报错! 相当于执行了 num.intValue()

建议修改为

java 复制代码
Integer x = null;
int y = (x == null) ? 0 : x;

包装类与基本类型的比较

当包装类与基本类型使用==比较时,包装类会自动拆箱为基本类型,此时比较的是数值,而不是地址。

java 复制代码
int a = 10;
Integer i = new Integer(100);
int j = 100;
System.out.println(i == j); // 输出 true (因为i自动拆箱了)
  • 装箱/拆箱是基本类型包装类之间的转换。
  • JDK 1.5+ 的自动装箱/拆箱是编译器语法糖 ,本质是调用 valueOf()xxxValue()
  • 常见坑:Integer==(缓存范围导致结果"看起来不一致")以及 null 拆箱导致 NPE。
相关推荐
麦兜顶当当1 小时前
subprocess与子进程交互
java·开发语言·jvm
Ulyanov2 小时前
基于Tkinter/ttk的现代化Python GUI开发全攻略:从布局设计到视觉美化(三)
开发语言·python·gui·tkinter·ttk
等风来Boy2 小时前
JAVA集成CAS客户端总结
java·cas
hutengyi2 小时前
go测试问题记录
开发语言·后端·golang
青槿吖2 小时前
第二篇:Spring Boot进阶:整合异常处理、测试、多环境与日志,开发稳得一批!
java·spring boot·后端·spring·面试·sqlserver·状态模式
星如雨グッ!(๑•̀ㅂ•́)و✧2 小时前
Spring WebFlux 中的并发
java·spring·oracle
weixin_433179332 小时前
python - 读写文件
开发语言·python
東雪木2 小时前
java学习—— 8 种基本数据类型 vs 包装类、自动装箱 / 拆箱底层原理
java·开发语言·java面试
Lyyaoo.2 小时前
【JAVA基础面经】JVM、JRE、JDK
java·开发语言·jvm