原始类型守性能底线,包装类补对象能力缺口;高频计算用原始类型,集合场景按需包装,方法边界优先原始入出,布尔状态用位运算优化。

用对基本类型和包装类,不是选谁、弃谁,而是让它们各司其职:原始类型守性能底线,包装类补对象能力缺口。协同的关键,在于“该用原始时绝不包装,该要对象时才升格”,避免无谓的装箱拆箱和内存浪费。
高频计算与循环场景:死守原始类型
所有涉及数值累加、索引遍历、计数器更新的路径,必须使用 int、long、double 等原始类型。自动装箱在循环中会反复触发 Integer.valueOf() 和 intValue(),每次都是对象分配 + GC 压力。
- ❌ 错误:用
Integer sum = 0做循环求和 → 每次+=都新建对象 - ✅ 正确:用
int sum = 0,结束后再按需转为Integer(如存入 Map 或返回 DTO) - 额外建议:数组优先用
int[]、long[];处理 10 万+ 数值时,比ArrayList节省约 30% 内存、降低 50%+ GC 频次
集合与泛型场景:按需包装,避免隐式转换
集合框架强制要求对象,所以 ArrayList 合法,但不等于最优。吞吐敏感场景下,应评估是否真需要“集合语义”:
- 若只是批量存取数值(如订单 ID 列表、统计直方图),优先考虑
int[]或第三方原生集合(如 Eclipse Collections 的IntList) - 若必须用集合,避免在循环内反复装箱:
list.add(i)(i 是 int)虽简洁,但底层仍是Integer.valueOf(i);可预缓存常用值(-128~127 范围内 Integer 已缓存) - 日志或监控埋点时,别把原始类型塞进集合再传参:
log.info("data={}", Collections.singleton(count))会多建 2 个对象;直接写log.info("count={}", count)更轻量
方法边界与跨层交互:原始入、原始出、包装仅作桥接
方法签名是性能边界的“门禁”。参数和返回值尽量用原始类型,把包装逻辑收束在最外层:
- ✅ 推荐签名:
public long calculateTotal(int count, double unitPrice) - ❌ 避免签名:
public Long calculateTotal(Integer count, Double unitPrice)→ 多余对象创建 + 可能 NPE - DTO 或 JSON 序列化时,字段声明仍可用包装类(如
Integer status),因为 null 可表达“未设置”语义;但内部计算过程全程用int,仅在构造响应体前做一次显式转换 - 数据库映射(如 MyBatis)同理:实体类字段可用
Integer接受 NULL,但业务逻辑层立刻转为int进行运算
布尔与状态位:能用位就不用对象
状态标识类场景最容易被忽略性能细节。boolean 原始类型仅占约 1 字节,而 Boolean 是完整对象(含对象头、引用、value 字段):
- 普通开关标志一律用
boolean,不要用Boolean - 多个相关状态(如权限位、配置开关)可合入一个
int,用位运算管理:flags |= (1 开启第 4 位,比维护 8 个Boolean字段节省空间且无 GC - 枚举(Enum)语义强、可读性好,但每个实例是堆对象;若仅需轻量状态流转(如 HTTP 状态码中间处理),优先用
int或byte,必要时再映射到 Enum
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











