Java只有值传递,即基本类型传值副本、引用类型传地址副本;可修改对象内部状态但无法改变原变量引用目标,String因不可变性表现特殊,数组和集合同理。

Java 中只有值传递,不存在引用传递——这是语言规范明确规定的事实。所谓“对象是引用传递”的说法,是把“传递了对象引用的副本”误读成了“传递了引用本身”,从而产生的一系列误解。
误解一:改了对象属性 = 引用传递
很多人看到方法内修改了对象的字段,外部变量也跟着变了,就认为“这不就是引用传递吗?”其实不是。真正发生的是:你传进去的是一个地址副本,它和原变量指向同一个堆内存对象,所以通过这个副本去操作对象内容(比如 person.setName("Tom")),自然会影响原始对象的状态。但这和“引用传递”有本质区别——你并不能让原变量指向新对象。
- ✅ 可以:通过参数副本调用 setXXX()、add()、append() 等方法改变对象内部状态
- ❌ 不可以:在方法内执行 p = new Person("Jack") 或 p = null,外部变量仍保持原引用不变
误解二:String 是“值引用”或“特殊传递”
String 看起来像值传递(比如 s = s + "!" 后原变量没变),常被误称为“值引用”。其实它仍是值传递,只是 String 类本身不可变:所有字符串操作都返回新对象,而原引用没被重新赋值。方法内对形参字符串的任何“修改”,实际是让形参指向了一个新字符串,原变量还指着旧的。
- 关键点:String 的 final byte[] value 和无修改接口,保证了“不可变性”
- 效果上:每次拼接、替换、截取,都是新建对象,不是改原对象
- 所以不是传递方式特殊,而是类型行为特殊
误解三:数组和集合是引用传递
数组和 ArrayList 等也是引用类型,传递的同样是引用的副本。你可以通过副本修改元素(arr[0] = 99、list.add(x)),但不能靠它改变原始变量的引用目标。
- ✅ list.add() 会反映到外部 list,因为操作的是同一堆对象
- ❌ list = new ArrayList() 在方法内执行后,外部 list 仍指向原来的对象
- 同理:arr = new int[]{1,2,3} 不会影响调用方的 arr 变量
一句话记住本质
Java 所有参数都是拷贝一份再传进去:基本类型拷贝数值,引用类型拷贝地址。拷贝的东西变了,不影响原件;但拷贝的地址能打开同一个保险柜,所以柜子里的东西可以被改——这不叫交出钥匙,只是给了把复制钥匙。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











