必须用包装类型的情形有四类:泛型、集合、反射、空值语义;自动装箱/拆箱存在缓存陷阱(-128~127)和空指针风险。

基本类型优先,包装类型只在必须时才用。
什么时候必须用包装类型
泛型、集合、反射、空值语义这四类场景无法使用基本类型:
- 集合类如
ArrayList<integer></integer>、Map<string boolean></string>要求元素是引用类型,int会编译失败 - 泛型擦除后类型信息丢失,
List<int></int>语法非法,JVM 不支持基本类型作为类型参数 - 反射调用方法时,若参数声明为
Integer,传入int值需自动装箱,但显式传Integer更安全(避免null导致的NullPointerException) - 需要表达“未设置”“缺失”含义时,比如数据库字段允许 NULL,用
Integer可区分0和null;而int只能用魔数(如-1)模拟,易出错
自动装箱/拆箱的坑在哪
看似方便,实则隐藏运行时开销和空指针风险:
-
Integer a = 127; Integer b = 127; System.out.println(a == b);输出true;但换成128就是false—— 因为Integer.valueOf()对[-128, 127]缓存重用对象,超出范围则新建实例 -
Integer x = null; int y = x;直接抛NullPointerException,拆箱不检查空值 - 循环中频繁装箱(如
for (int i = 0; i )会创建大量临时对象,GC 压力上升 - 比较两个包装类型应始终用
.equals(),而非==(除非明确要比较引用)
性能敏感场景怎么选
数值计算、数组密集存储、高频循环体里,基本类型是唯一合理选择:
立即学习“Java免费学习笔记(深入)”;
-
int[]比Integer[]内存占用小得多:前者是连续的 4 字节整数块;后者是对象引用数组,每个元素指向堆上独立的Integer实例(至少 16 字节+) - 数学运算如
a + b * c,用int是纯 CPU 指令;用Integer会隐式拆箱 → 运算 → 装箱,多出至少三次对象操作 - 使用
OptionalInt、IntStream等原始类型特化 API,比Optional<integer></integer>或Stream<integer></integer>更高效,避免中间装箱
最常被忽略的是:泛型容器和空值语义不是“可选优化”,而是设计契约的一部分;一旦选错类型,后期很难安全替换——比如把 Integer 改成 int,所有可能为 null 的路径都会崩。宁可早一点明确语义,也不要靠注释或约定来弥补类型缺失。










