Java中基本类型值存栈,包装类引用存栈、对象存堆;装箱拆箱有堆栈开销,小整数和字符串字面量在堆内常量池缓存复用。

基本类型变量:值直接在栈上
int、boolean、char 等 8 种基本类型,变量声明即在栈中分配空间,值就存在那里。
- 例如 int x = 10;:x 这个变量名和数值 10 都在栈帧里,方法结束,x 自动消失
- 传参时是值拷贝:foo(x) 会把 10 复制一份进新栈帧,原 x 不受影响
- 栈里不存地址,也不涉及引用——它就是纯数据本身
包装类变量:引用在栈,对象在堆
Integer、Boolean、Character 等包装类是真正的类,用 new 或自动装箱创建的实例,本质是对象。
- Integer a = new Integer(42);:a 这个引用变量在栈中,而 new 出来的 Integer 对象在堆中
- Integer b = 100;(自动装箱):JVM 调用 Integer.valueOf(100),通常从缓存(-128 到 127)取已有对象,b 引用仍存栈,对象实体仍在堆(或常量池缓存区)
- 多个包装变量可能指向同一个堆对象(如 b == c 在小整数范围内可能为 true),但它们各自的引用变量都独立存在于栈
装箱与拆箱:隐式操作背后的堆栈开销
自动装箱(基本类型 → 包装类)会触发对象创建,自动拆箱(包装类 → 基本类型)需从堆中读取值——这些都不是零成本操作。
- 频繁装箱(如循环中 list.add(i),i 是 int)→ 每次都可能新建 Integer 对象 → 堆压力增大、GC 频率上升
- 拆箱时若对象为 null,运行时报 NullPointerException(因为要从 null 引用取值)
- 避免在性能敏感路径(如高频计算、集合遍历)中依赖自动装箱;优先用基本类型数组或专用集合(如 IntArrayList)
常量池与缓存的特殊位置
字符串字面量和小范围整数包装对象,虽属对象,但 JVM 会做优化,复用已有实例——它们仍位于堆中(JDK 7+ 后常量池已移入堆),只是不重复创建。
立即学习“Java免费学习笔记(深入)”;
- String s = "hello";:s 引用在栈,"hello" 字面量存在堆内的字符串常量池
- Integer i = 127; 和 Integer j = 127; → i == j 为 true(指向同一缓存对象)
- Integer m = 128; 和 Integer n = 128; → m == n 通常为 false(超出缓存范围,各自 new)


















