java参数传递本质是值传递:基本类型传值拷贝,引用类型传地址值拷贝;改对象属性影响外部,改引用指向则不影响。

Java 中参数传递的本质是“值传递”,但要真正搞懂,关键不是背结论,而是看清每一步在内存中发生了什么。核心就两点:栈里存什么、堆里放什么,以及它们怎么连起来。
看清楚栈帧的复制行为
每次方法调用,JVM 都会为它创建一个独立的栈帧。这个帧里装着形参和局部变量——它们全在栈上,彼此隔离。
- 基本类型(如 int、boolean):实参的值被完整拷贝进形参所在的栈帧,两个变量互不干扰
- 引用类型(如 Person、ArrayList):实参变量里存的是地址(比如 0x1000),拷贝的正是这个地址值,不是对象本身
- 形参改名、重新赋值(如 param = new Person("Tom")),只改自己栈帧里的地址,不影响外面那个变量
区分“改对象”和“改引用”
这是最容易混淆的地方。同一块堆内存,可以被多个栈上的引用指向;只要没换地址,改的就是同一个对象。
- 能影响外部:param.name = "Lucy" → 修改堆中 Person 对象的 name 字段
- 不影响外部:param = new Person("Jack") → 只让 param 指向新对象,原变量仍指着旧地址
- 验证技巧:用 System.identityHashCode(obj) 打印哈希值,相同说明指向同一对象
结合堆与栈画简易内存图
动手画两栏:左边标“栈(main)”,右边标“栈(method)”,下方画“堆”。按执行顺序填内容,比纯读代码直观得多。
- main 中 Person p = new Person("Amy") → 栈里 p 存 0x2000,堆 0x2000 存 name="Amy"
- 调用 change(p) → method 栈帧里多一个形参变量,也存 0x2000
- change 内部 p.name = "Ben" → 堆 0x2000 的 name 变成 "Ben",main 的 p 还指着它
- change 内部 p = new Person("Cal") → method 栈里 p 改成新地址(如 0x3000),main 的 p 不变
用 args 数组验证引用传递的错觉
main 方法的 String[] args 是典型引用类型参数,但它能帮你打破“传对象=传引用”的误解。
- 你在 main 里写 args = new String[]{"X"},不会改变命令行实际传入的内容
- 但写 args[0] = "Y",如果 args 非 null,确实会改掉第一个参数的值——因为改的是堆里数组对象的元素
- 这再次说明:副本地址没变,你就能操作原对象;副本地址一换,就和原来没关系了
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











