Java只有值传递,即方法调用时实参的值(基本类型为数据本身,引用类型为地址)被复制给形参;所谓“引用传递”是误解,因形参只能修改对象状态,不能改变实参引用本身。

Java 中只有值传递,这是由语言规范决定的——方法调用时,实参的“值”被复制给形参,无论这个值是基本类型的数据,还是引用类型的地址。所谓“引用传递”的错觉,源于对“引用值”本身的误解。
基本类型:值就是数据本身
传入 int、char、boolean 等类型时,拷贝的是该变量在栈中存储的实际数值。方法内修改形参,不影响原变量。
例如:
void change(int x) { x = 100; }
int a = 5;
change(a);
// a 仍是 5
立即学习“Java免费学习笔记(深入)”;
这里 x 是 a 的副本,修改 x 只改了副本,原 a 毫无影响。
引用类型:值是对象地址,不是对象本身
传入 String、ArrayList、自定义类等时,拷贝的是“指向堆中对象的引用地址”,这个地址本身是值(比如 0x7f8a…),所以仍是值传递。
关键点在于:你无法通过形参改变原始引用变量所存的地址,但能通过该地址访问并修改堆中对象的状态。
例如:
void modifyList(ArrayList<String> list) {
list.add("new"); // ✅ 修改对象内容
list = new ArrayList<>(); // ❌ 仅改形参指向,不影响实参
}
ArrayList<String> arr = new ArrayList<>();
arr.add("old");
modifyList(arr);
// arr.size() == 2,且包含 "old" 和 "new"
第一行修改生效,是因为 list 和 arr 指向同一对象;第二行赋值无效,是因为只改变了形参 list 存的地址,没动 arr 变量里存的那个地址。
用原生代码对比验证:没有修改实参引用的能力
如果 Java 支持引用传递,就应能写出让外部变量指向新对象的代码。但实际做不到——下面这段看似“交换”,实则无效:
void swap(Person a, Person b) {
Person tmp = a;
a = b;
b = tmp;
}
Person p1 = new Person("Alice");
Person p2 = new Person("Bob");
swap(p1, p2);
// p1 仍是 Alice,p2 仍是 Bob
因为 a 和 b 只是 p1、p2 所存地址的副本,交换它们,不等于交换 p1、p2 本身。
终极证据:JVM 层面的参数压栈行为
Java 字节码(如 invokestatic)调用方法时,所有参数都以“值”形式从操作数栈弹出,复制到新栈帧的局部变量表中。JVM 规范中从未定义“引用传递”指令,只有 iload(取 int 值)、aload(取 reference 值)——两者都是加载一个值,只是类型不同。
也就是说:不管是 int 还是 Person,传进去的都是一个确定的、可拷贝的值——要么是 4 字节整数,要么是 4 或 8 字节内存地址。


















