基本类型变量存值于栈,包装类型对象存于堆、栈中仅存引用;==比较基本类型比值、包装类型比引用(小整数缓存内可能为true);应优先用objects.equals()避免空指针。

基本类型和包装类型在内存中的位置不同
Java 的基本类型(如 int、boolean、double)变量直接存值,分配在栈上;而包装类型(如 Integer、Boolean、Double)是对象,实例存在堆中,栈里只存引用。
这意味着:传参时基本类型是值拷贝,包装类型是引用拷贝(但注意——由于不可变性,多数操作实际会新建对象)。
-
int a = 5; int b = a;→b是独立副本,改b不影响a -
Integer x = 5; Integer y = x;→ 初始时y和x指向同一对象(尤其小整数走缓存),但y = y + 1会触发自动拆箱+装箱,生成新Integer实例
== 比较时行为差异极大
用 == 比较基本类型,比的是值;比较包装类型,比的是引用地址——除非两个变量恰好指向同一个缓存对象。
常见陷阱:
立即学习“Java免费学习笔记(深入)”;
Integer a = 127; Integer b = 127; System.out.println(a == b); // true(缓存范围 -128~127)Integer c = 128; Integer d = 128; System.out.println(c == d); // false(超出缓存,各自 new)Integer e = null; e == 0 // 编译通过但运行报 NullPointerException
安全做法始终用 .equals(),但要注意左操作数非 null,或改用 Objects.equals(a, b)。
自动装箱/拆箱带来隐式开销和空指针风险
编译器会在需要时自动调用 valueOf()(装箱)和 xxxValue()(拆箱),看似方便,实则暗藏问题。
- 循环中频繁装箱(如
for (int i = 0; i )会创建大量短命 <code>Integer对象,加重 GC 压力 -
Integer x = null; int y = x;→ 运行时报NullPointerException,因为拆箱时调用x.intValue() -
Boolean flag = null; if (flag) { ... }→ 同样触发拆箱,NPE
数据库字段映射、JSON 反序列化等场景中,包装类型常为 null,务必检查再拆箱。
泛型和集合必须使用包装类型
Java 泛型不支持基本类型,所以 List<int></int> 是非法的,必须写 List<integer></integer>。这导致集合操作天然引入装箱/拆箱。
- 性能敏感场景(如高频数值计算、大数据量缓存)应避免用
ArrayList<integer></integer>存大量整数,可考虑int[]或第三方库(如 Eclipse Collections 的IntArrayList) -
Map<string int></string>编译失败,只能用Map<string integer></string>,此时map.get("key")返回null,不能直接赋给int - 使用
OptionalInt等原始类型特化类,比Optional<integer></integer>更省内存且避免装箱
最易被忽略的一点:缓存策略不是规范强制,而是 OpenJDK 实现细节;不同 JDK 版本或厂商(如 GraalVM)可能调整 Integer.valueOf() 缓存范围,不要依赖它做逻辑判断。










