基本类型不能为null,包装类型可以;int等值类型栈上存储、不可空,Integer等引用类型堆上存储、可为null,易在数据库映射、JSON反序列化时因自动拆箱导致NullPointerException。

基本类型不能为 null,包装类型可以
Java 的 int、boolean、double 等基本类型是值语义,直接存数据,栈上分配,天生不能为 null;而 Integer、Boolean、Double 这些包装类型是对象,堆上分配,可以为 null。这是最常踩坑的地方——尤其在数据库映射、JSON 反序列化或方法参数校验时。
- MyBatis 查询结果字段为
NULL,对应int字段会报NullPointerException(自动拆箱失败),换成Integer就能接住 - Spring MVC 接收 JSON 里缺失的数值字段:用
int会直接 400 报错,用Integer则为null,可后续判空处理 -
Boolean flag = null;合法;boolean flag = null;编译不通过
自动装箱/拆箱不是免费的,有性能和陷阱
Java 在 == 比较、赋值、方法调用时会隐式触发装箱(int → Integer)或拆箱(Integer → int)。看似方便,但容易引发 NullPointerException 或意外的比较结果。
- 拆箱时遇到
null直接抛NullPointerException:Integer a = null; int b = a; // 运行时报错
-
==比较行为不一致:Integer x = 127; Integer y = 127; System.out.println(x == y); // true(缓存命中) Integer m = 128; Integer n = 128; System.out.println(m == n); // false(超出 IntegerCache 范围)
推荐统一用.equals()比较包装类型 - 循环中频繁装箱(如
for (int i = 0; i )会显著增加 GC 压力,应避免
泛型、集合、反射只接受包装类型
Java 泛型擦除后实际操作的是 Object,而基本类型不是 Object 子类,因此 List、Map 全部非法。所有集合、函数式接口(如 Function)、注解属性、反射获取的字段类型,都必须用包装类。
-
ArrayList编译失败,必须写ArrayList - 使用 Stream 处理数值:没有
IntStream时,list.stream().map(Integer::parseInt)返回的是Stream,不是原始int流 - 注解中定义默认值:
@interface Config { int value() default 0; }实际声明的是包装类语义,底层仍走Integer,但语法糖隐藏了
内存占用与默认值差异明显
基本类型固定占栈空间(如 int 恒为 4 字节),无默认引用开销;包装类型除了字段值,还包含对象头、类元信息、GC 标记等,一个 Integer 实例通常至少占用 16 字节(64 位 JVM + 压缩指针)。同时,它们的“默认值”语义不同:
立即学习“Java免费学习笔记(深入)”;
- 成员变量未显式初始化:
int默认为0,Integer默认为null - 局部变量必须显式初始化,否则编译报错——无论基本还是包装类型
- 数组创建时:
new int[10]所有元素为0;new Integer[10]所有元素为null










