Java所有参数均为值传递:基本类型传数值副本,修改不影响实参;引用类型传地址副本,可修改对象内容但不能改变实参引用指向。

Java 方法内部对入参的操作结果,不能靠“直觉”猜,而要依据一个统一原则:所有参数都是值传递。关键在于分清“值”是什么——对基本类型,是数据本身;对引用类型,是对象的内存地址。
基本类型参数:改不着原变量
传进去的是数值副本,方法内任何修改(++、赋值、运算)都只影响形参,不影响调用方的实参。
- 比如 int a = 5; 调用 foo(a),foo 内把形参改成 100,main 里的 a 还是 5
- 即使在方法里重新赋值、做算术、甚至用临时变量中转,都不改变原始变量
- 想让外部变量变化,就得让方法返回新值,再由调用方主动赋值回去
引用类型参数:能改对象内容,但换不了引用本身
传进去的是对象地址的副本。这个副本和实参指向同一个堆内存对象,所以通过它能修改对象内部状态(如数组元素、对象字段),但不能让实参指向另一个新对象。
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
- student.setName("张三") → 外部 student 的 name 真的变了
- arr[0] = 99 → 外部数组首元素真的变了
- 但 s = new Student() 或 arr = new int[]{1,2} → 只是让形参指向新对象,对外部无影响
- swap(Student s1, Student s2) 无法交换两个实参的引用,原因就在这里
常见误判场景与验证方式
遇到拿不准的操作,按两步走:先看传的是什么值,再看这个值被用来干什么。
立即学习“Java免费学习笔记(深入)”;
- 如果操作的是“值本身”(如 int x = x + 1),那就是改副本,不影响外边
- 如果操作的是“值所指向的内容”(如 list.add()、map.put()、obj.field = xxx),那就可能影响外边
- 写个最小可运行例子,打印调用前后变量状态,比背结论更可靠
- IDE 调试时观察变量内存地址(比如 toString() 输出的哈希码),能直观确认是否指向同一对象
设计时的应对建议
与其纠结“能不能改”,不如从意图出发设计参数行为。
- 只读用途:用 final 修饰形参,避免意外修改,也向调用方传递明确语义
- 需要输出新状态:返回新对象(如 String.toUpperCase() 返回新串),而不是试图修改入参
- 必须批量修改多个字段:封装成 Builder 或使用 @Builder 注解,避免传一堆零散参数
- 避免“一边读一边改”:比如方法既遍历 List 又往里 add,容易引发 ConcurrentModificationException,应拆开或加锁

















