Java等语言中对象传递本质是值传递,传的是地址副本;可修改对象属性但无法改变实参变量指向,基本类型与引用类型均遵循此规则。

对象传的是“地址副本”,不是“引用本身”
Java、PHP等语言中,对象变量存储的并不是对象数据,而是指向堆内存中对象的地址(或句柄)。当把对象作为参数传入方法时,系统复制的是这个地址值,再把副本交给形参——这仍是值传递,只是“值”是地址而已。形参和实参各自持有独立的变量空间,但初始时指向同一块对象内存。
所以你能修改对象属性(比如 user.name = "Tom"),是因为你用副本地址找到了原对象;但如果你在方法里让形参指向新对象(p = new User()),外部实参完全不受影响——因为它持有的还是原来的地址副本。
基本类型与引用类型,都是值传递,只是“值”的含义不同
很多人误以为“int 是值传递,User 是引用传递”,其实二者统一:都是传值,区别只在于传的内容是什么。
- 基本类型(如
int、boolean):传的是具体数值的副本(如5→ 复制出另一个5) - 引用类型(如
User、ArrayList):传的是内存地址的副本(如0x1234→ 复制出另一个0x1234)
两者都满足“形参修改不影响实参变量本身”的值传递定义,只是后者因共享对象实例,容易让人产生“被改了”的错觉。
真正能改变实参变量本身的,只有显式引用绑定
真正的引用传递,要求形参和实参是同一个变量的两个名字(即别名),修改形参等于直接修改实参变量。这在 Java 中不存在;但在 PHP 中可用 & 实现,在 C++ 中可用 & 引用声明,在 C# 中可用 ref 关键字。
例如 PHP:
$a = new User();<br>$b = &$a; // $b 是 $a 的引用,不是副本<br>$b->name = "Alice";<br>echo $a->name; // 输出 Alice —— $a 变量本身被牵动
而 $b = $a; 只是赋值句柄,$b 和 $a 是两个独立变量,只是碰巧指向同一个对象。
判断是否影响外部,关键看操作对象还是操作变量
一句话区分行为本质:
-
改对象内部状态(如
list.add()、sb.append()、obj.field = x)→ 外部可见变化(因共用对象) -
改变量指向关系(如
list = new ArrayList()、obj = new User())→ 外部无影响(因只动了副本)
面试常考的 swap、reassign、append 对比题,核心就在这里:不是“对象能不能被改”,而是“你改的是对象,还是那个装着地址的盒子”。










