必须用包装类的场景:泛型参数(如List<Integer>)、POJO/DTO字段(需支持null)、方法返回Object类型;核心原因在于语法硬限制、null安全性及面向对象需求;混淆踩坑点集中于==比较(受-128~127缓存影响)、自动拆箱NPE和内存性能损耗。

直接说重点:基本类型和包装类的混淆,不是记不住名字,而是没理清“什么时候必须用哪个”“为什么这样设计”“哪里一踩就崩”。补漏的关键是抓住三个锚点——null 安全性、泛型约束、缓存机制。下面分四块讲清楚。
哪些地方必须用包装类,不能用基本类型
这不是风格问题,是语法硬限制:
- 泛型参数:List<Integer> 合法,List<int> 编译报错,因为泛型擦除后只认 Object 及其子类,而 int 不是类
- POJO/DTO 字段:数据库查出来可能是 null,如果字段声明为 int,反序列化或赋值时遇到 null 就会触发自动拆箱,抛出 NullPointerException
- 方法参数或返回值需统一为 Object 类型:比如 Map 的 value 是 Object,你传 int 会强制装箱;回调接口定义为 Function<String, Object>,你也只能返回包装类
== 比较为什么有时 true 有时 false
根本原因在 Integer.valueOf() 的缓存策略:
- 默认缓存范围是 -128 到 127(可由 JVM 参数 -Djava.lang.Integer.IntegerCache.high 调整)
- Integer a = 127; Integer b = 127; → a == b 是 true(指向同一个缓存对象)
- Integer a = 128; Integer b = 128; → a == b 是 false(各自 new 出来的新对象)
- 只要涉及对象引用比较,一律用 equals();数值比较才用 ==,且确保两边都不是 null
空指针陷阱怎么提前发现
包装类默认值是 null,但基本类型有默认值(如 int 是 0),这个差异在运行时极隐蔽:
立即学习“Java免费学习笔记(深入)”;
- 成员变量未显式赋值:Integer field; → 值为 null;int field; → 值为 0
- 从 JSON 或数据库读取数据后直接拆箱:Integer code = json.get("code"); int c = code; → code 为 null 时立即 NPE
- 修复方式:优先使用 Objects.equals(a, b) 比较;拆箱前加 Objects.nonNull() 判空;或用 Optional.ofNullable(code).orElse(0)
性能与内存开销的真实差距
不是“能用包装类就不用基本类型”,而是要懂代价:
- Integer 对象比 int 多占至少 12 字节(对象头 + 压缩指针 + 实际值),高频循环中创建上万 Integer,GC 压力明显上升
- 自动装箱发生在每次赋值、传参、返回时,背后是隐式调用 valueOf() 和 intValue(),看似简洁,实则藏了方法调用和对象分配
- 推荐做法:计算密集型逻辑(如算法题、批量数值处理)坚持用基本类型;仅在需要对象语义时(集合、泛型、可空性)切换为包装类


















