Java所有参数都是按值传递,对象参数传的是引用的副本;修改形参指向新对象不影响外部变量,但通过形参修改对象内容会影响原对象。

Java 中方法内对对象参数重新赋值,外部变量不变,根本原因在于:Java 所有参数都是按值传递,对象类型传的是引用的副本,不是引用本身。
传的是“地址的拷贝”,不是“地址本身”
当你写 Person p = new Person("Alice"),变量 p 存储的是堆中那个对象的内存地址。调用方法时,JVM 把这个地址值复制一份传进去——形参拿到的是副本,和原变量各自独立。
- 修改形参指向新对象(如 person = new Person("Bob")),只改了副本里存的那个地址值
- 原变量 p 里存的地址没动,仍指着原来的对象
- 就像把一张地图复印件交给别人,他在复印件上画个新地标,不会改变你手里的原图
能改对象内容,但改不了谁在“持有”它
虽然形参是副本,但它和原引用指向同一块堆内存。所以通过形参调用方法或修改字段,确实会影响原对象:
- person.setName("Bob") → 修改堆中对象的 name 字段,外部可见
- list.add("x") → 修改 ArrayList 内部数组,外部 list 内容同步更新
- 但 person = null 或 list = new ArrayList() → 只让形参“松手”,不牵动外面那个变量
String 和 Integer 的表现也源于此
它们不是机制特殊,而是类设计使然:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
- String 不可变:任何“修改”(如 s += "!")都生成新对象,形参随之指向新地址,原引用仍指旧字符串
- Integer 有缓存:Integer i = 127 和 i = i + 1 可能复用缓存对象,也可能新建;但无论哪种,i = ... 都只是重设形参指向,不影响外部变量持有的引用
- 用 == 比较 Integer 得到意外结果,本质也是因为装箱后可能指向不同对象,而非传递方式变了
验证方法很简单:看“重新赋值”是否生效
最直接的判断标准就是这一句:
- 在方法里给形参赋一个新对象(obj = new Xxx() 或 obj = null),执行完后外部变量是否变了?
- 如果没变 → 就是值传递(Java 确实如此)
- 如果变了 → 才是引用传递(Java 从不存在)
这个测试不依赖对象可不可变、有没有缓存,直击传递机制本质。

















