Java中所有方法参数都是值传递,基本类型传值副本,对象类型传引用副本,形参重赋值不影响实参,但通过引用修改对象状态会影响实参。

Java中所有方法参数都是值传递
Java没有引用传递,哪怕你传的是对象,本质上传的也是“引用的副本”。这意味着方法内部对形参变量的重新赋值(比如 obj = new Object())不会影响调用方的原始变量;但通过该引用修改对象状态(比如 obj.setName("xxx"))会生效——因为副本和原引用指向同一个堆内存地址。
基本类型参数传递:复制栈上数值
传 int、boolean、double 等时,直接把值拷贝一份进方法栈帧。方法内改它,对外零影响。
常见错误现象:
- 以为在方法里改了 int x 就能改变外部变量值
- 把交换两个整数的逻辑写成 swap(int a, int b) 并期待调用后原变量互换
实操建议:
- 需要返回新值就用 return
- 要交换多个基本类型,考虑封装进数组或自定义容器类(如 IntWrapper)
- 别试图靠参数“输出”基本类型结果
对象类型参数传递:复制引用值,不是复制对象
传 String、ArrayList、自定义类实例时,实际上传的是指向堆中对象的引用值(一个内存地址的拷贝)。这个拷贝和原引用内容相同,但它们是两个独立变量。
使用场景与陷阱:
- ✅ list.add("item") 生效:操作的是同一对象
- ❌ list = new ArrayList() 失效:只是让形参指向新对象,原变量不变
- ⚠️ String 看似“不可变”,所以 s = s + "x" 实际创建新字符串,不影响外部 s
性能提示:
- 不会因传对象而触发深拷贝,开销小
- 但要注意并发场景下多个引用同时修改同一对象可能引发竞态
数组和集合类参数的典型误用
数组是对象,所以传的是引用副本。但新手常混淆“数组变量重赋值”和“数组元素修改”:
立即学习“Java免费学习笔记(深入)”;
示例对比:void modifyArray(int[] arr) { arr[0] = 999; } → 外部数组首元素被改void replaceArray(int[] arr) { arr = new int[]{1,2,3}; } → 外部数组完全不受影响
容易踩的坑:
- 在方法里用 Arrays.asList() 包装数组后调用 add(),抛 UnsupportedOperationException(因为返回的是固定大小列表)
- 把 ArrayList 传入方法后清空它(clear()),调用方数据也丢了 —— 这是预期行为,不是 bug,但常被忽略
- 用 stream().filter(...).collect(...) 生成新集合时,原集合不变;但若用 removeIf(),原集合就被改了
真正难处理的是需要同时改变多个输入变量的状态,或者想避免调用方对象被意外修改。这时候得靠防御性拷贝、不可变封装,或者干脆重构为返回新对象 —— 而不是指望“传引用就能改外面”。










