引言
在 Java 中,方法调用时参数的传递方式常常让初学者困惑。有人说“Java 是引用传递”,也有人说“Java 是值传递”。本文将通过示例和类比,带你彻底搞清 Java 的参数传递机制——值传递(Pass-by-Value)。
一、什么是值传递?
- 值传递:调用方法时,Java 会将实参的 值 复制一份,传给形参。
- 对于基本类型,这个“值”就是数据本身;
- 对于引用类型,这个“值”则是对象在堆上的 引用(地址)的副本。
核心结论
无论是基本类型还是引用类型,Java 方法拿到的都是值的拷贝,而不是实参变量本身。
二、基本类型的值传递示例
public class PrimitiveDemo {
public static void main(String[] args) {
int x = 5;
modifyPrimitive(x);
System.out.println(x); // 仍输出 5
}
static void modifyPrimitive(int value) {
value = 10; // 只改变了值的副本
}
}
- 调用
modifyPrimitive(x)
时,x
(值为 5)被复制给value
。 - 方法内改变
value
并不影响外部的x
,因为它们不是同一块内存。
三、引用类型的“值传递”示例
class Person {
String name;
Person(String name) { this.name = name; }
}
public class ReferenceDemo {
public static void main(String[] args) {
Person p = new Person("Alice");
changeName(p);
System.out.println(p.name); // 输出 "Bob"
resetReference(p);
System.out.println(p.name); // 依然输出 "Bob"
}
static void changeName(Person person) {
// person 和 p 都指向同一个堆对象的引用副本
person.name = "Bob"; // 修改对象内容
}
static void resetReference(Person person) {
// 下面这行只是改变了“参数变量”的引用
person = new Person("Charlie");
person.name = "Charlie"; // 只影响方法内部的 person
}
}
changeName
:修改对象字段,外部可见。resetReference
:重新赋值给person
,仅影响本地副本,不会改变main
中的p
。
四、与引用传递的对比
特性 | 引用传递(Pass-by-Reference) | 值传递(Pass-by-Value) |
---|---|---|
传递内容 | 变量本身的地址 | 变量的值(基本类型)或引用的副本 |
方法内重新赋值可见 | 会改变调用者的变量 | 不会影响调用者的变量 |
Java 支持情况 | 不支持 | 支持,且唯一的传参方式 |
如果 Java 是引用传递,那么
resetReference
中的person = new Person("Charlie")
应该改变外部p
,但事实并非如此。
五、直观类比
-
值传递 → 传递的是“文档的复印件”:
你给朋友一份复印件,他在复印件上涂改内容,不会影响你手里的原件;
他换了一份新复印件,也不会让你的原件被替换。 -
引用类型的值传递 → 复印件上写的是“档案柜编号”,两份复印件的编号都一样,指向同一个档案柜;
修改档案柜里的文件,所有复印件都能“看到”变化;但换编号的操作只是对复印件本身生效。
六、小结
- Java 只支持值传递:无论基本类型还是对象引用,传递的都是值的副本。
- 引用类型传递的是引用的副本:方法内可通过它操作同一个堆对象,但无法改变调用者的引用指向。
- 牢记本质:值传递让参数调用更加安全可控,也避免了引用传递可能带来的意外副作用。
掌握了 Java 的参数传递机制,就能更自信地编写和调试方法调用,避免“修改不生效”或“意外修改外部变量”的困惑。