java中栈帧只存对象引用而非对象本身,引用指向堆中对象实例,多态不影响该机制,仅影响运行时方法分派。

Java 中对象本身不保存在栈帧里,栈帧只存“指向对象的引用”,真正的对象实例始终在堆中。方法调用时的状态保存,核心是靠栈帧结构把局部变量、参数、执行上下文隔离并固化下来。
栈帧里存什么:引用而非对象
当一个方法接收对象参数或声明对象类型局部变量(如 String s = new String("abc");),栈帧的局部变量表中存放的只是堆中该字符串对象的内存地址(HotSpot 默认使用直接指针方式)。这个地址就是“引用”,它轻量、固定大小(通常 4 或 8 字节),能快速入栈出栈。
也就是说:
- 堆负责存储对象的完整状态(字段值、数组元素等);
- 栈帧只负责记录“此刻我正在操作哪个对象”,靠引用建立连接;
- 多个栈帧可以同时持有同一个堆对象的引用,互不影响。
方法调用时如何关联对象
每次调用方法,JVM 都会创建新栈帧,并按以下步骤完成对象引用的传递与保存:
- 调用方把实参(可能是对象引用)从自己的局部变量表或操作数栈复制到被调用方法栈帧的局部变量表对应槽位;
- 若方法内新建对象(如 new ArrayList()),new 指令在堆分配空间,再把生成的引用写入当前栈帧的局部变量表;
- 方法内部对对象的读写(如 list.add("x")),本质是通过栈帧里的引用找到堆中对象,再修改其字段或调用其方法。
方法结束时对象会不会丢
方法执行完,栈帧弹出,局部变量表清空——所有存在其中的对象引用都消失。但这不等于对象被销毁:
- 如果该对象只有这一个引用,且没被其他栈帧、静态变量、集合、线程或外部系统持有着,它就变成不可达对象,等待 GC 回收;
- 如果对象被返回(return obj;)、赋给成员变量、放进 Map 或 List、传给另一个线程,那堆中的对象会继续存活,不受原栈帧销毁影响。
为什么局部内部类能“记住”方法里的变量
局部内部类实例虽然定义在方法内,但它自己是堆对象。编译器会把被它访问的局部变量(必须是 effectively final)复制一份,作为隐式字段嵌入到该内部类实例中。这样即使方法栈帧没了,内部类对象仍带着那些值的副本在堆里运行。
这不是栈帧“延长寿命”,而是编译期做了数据迁移——把栈上即将消失的值,提前固化进堆对象里。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











