说实话,基本类型在 Java 里就像老黄牛——干活实在,不花哨。尤其在高频计算、集合操作和并发场景中,用对了基本类型,性能提升是肉眼可见的。关键不是“能不能用”,而是“在哪用、怎么用、为什么这么用”。

避免装箱拆箱:让 int 真正保持原始状态
包装类(比如 Integer)每次自动装箱或拆箱都会创建对象、触发 GC,开销远超你想象。循环累加、数组遍历、计数器这类场景,必须使用原始类型,没有商量余地。
- 错误写法:
Integer sum = 0; for (int i = 0; i < n; i++) sum += i;—— 每次+=都会发生一次装箱再加拆箱,对象大量产生。 - 正确写法:
int sum = 0; for (int i = 0; i < n; i++) sum += i;干净利落,不产生额外开销。 - 集合场景注意:
ArrayList存储的是对象,而非 int。如果只涉及数值运算且数据量较大,建议考虑第三方库(如 Eclipse Collections 的 IntList)或直接用数组替代。
数组优先于泛型集合:类型明确且操作简单时选择数组
基本类型数组(int[]、double[])没有泛型擦除带来的开销,内存连续、访问速度快、无引用间接跳转,JIT 也更容易优化。这类数据结构的性能表现非常出色。
- 适用场景:缓存批量 ID、统计直方图、数学计算中间结果、DTO 字段序列化前的临时结构。这些都是典型的硬性需求。
- 对比示例:处理 10 万条订单金额时,使用
double[]比ArrayList节省约 30% 内存,GC 压力降低 50% 以上——数据足以说明问题。 - 补充技巧:配合
Arrays.sort()、System.arraycopy()等原生方法,比使用 Stream 或 Collections 工具类轻量得多。
局部变量与方法参数:用原始类型守住性能边界
栈上分配的原始类型访问速度极高,且不受 GC 影响。将性能敏感路径中的包装类参数、返回值、中间变量全部还原为原始类型,这项优化带来的回报非常高。
- 方法签名优化:
public long calculateTotal(int count, double unitPrice)比public Long calculateTotal(Integer count, Double unitPrice)更直接、更安全,也更节省内存。 - 避免“隐式逃逸”:不要将原始类型临时包装成对象再传给日志框架或监控埋点。例如
log.info("count={}", count)是安全的;但log.info("data={}", Collections.singleton(count))就会引入不必要的对象——画蛇添足。 - 布尔与枚举:
boolean比Boolean更省空间。状态标志优先使用boolean或位操作(例如用 int 的低 8 位表示 8 种开关),而非 Enum 对象(除非需要语义强约束,则另当别论)。
与 JVM 协同:理解底层如何对待基本类型
基本类型是 JVM 指令集的一等公民。掌握这一点,能够避开许多“看似合理实则拖慢”的设计。
- 字节码层面:
iload、istore、iadd等指令专为 int 设计,执行周期短;而invokestatic Integer.valueOf()则多出方法调用加对象分配,差距显而易见。 - JIT 优化友好:循环中纯 int 运算大概率被内联、向量化(如自动 SIMD 加速),而 Integer 对象无法享受这类优化——先天不足。
- 注意边界:
long和double虽是基本类型,但在 32 位 JVM 上可能无法保证原子读写(现代 64 位环境基本无此问题,但稳妥起见,用volatile修饰时配合AtomicLong更可靠)。
