Java中方法的参数传递机制是值传递,这是Java语言规范明确规定的核心特性,不过很多开发者因为引用类型参数传递时的表现,容易误认为是引用传递,下面我们通过具体案例来深度解析这个机制。

什么是值传递和引用传递
要理解Java的参数传递,首先需要明确两个概念的定义:
- 值传递:方法调用时,实际参数的值会被复制一份传递给形式参数,形参拿到的是实参的副本,对形参的修改不会影响原来的实参。
- 引用传递:方法调用时,实际参数的引用(内存地址)直接传递给形式参数,形参和实参指向同一个内存地址,对形参的修改会直接影响实参。
基本数据类型的参数传递验证
基本数据类型(byte、short、int、long、float、double、char、boolean)的参数传递,很容易验证是值传递,我们看下面的代码示例:
public class ValuePassTest {
public static void main(String[] args) {
int num = 10;
System.out.println("修改前num的值:" + num);
changeNum(num);
System.out.println("修改后num的值:" + num);
}
private static void changeNum(int param) {
param = 20;
System.out.println("方法内param的值:" + param);
}
}
运行上述代码,输出结果如下:
修改前num的值:10 方法内param的值:20 修改后num的值:10
可以看到,我们在changeNum方法内修改了形参param的值,但是实参num的值并没有发生变化,说明基本数据类型传递的是值的副本,属于典型的值传递。
引用数据类型的参数传递验证
引用数据类型(类、数组、接口等)的参数传递是很多开发者产生误解的地方,我们看下面的案例:
class User {
String name;
int age;
User(String name, int age) {
this.name = name;
this.age = age;
}
}
public class ReferencePassTest {
public static void main(String[] args) {
User user = new User("张三", 18);
System.out.println("修改前user的age:" + user.age);
changeUser(user);
System.out.println("修改后user的age:" + user.age);
}
private static void changeUser(User param) {
param.age = 20;
System.out.println("方法内param的age:" + param.age);
}
}
运行上述代码,输出结果如下:
修改前user的age:18 方法内param的age:20 修改后user的age:20
这里看起来形参的修改影响了实参,很多开发者会误以为是引用传递,但实际上这里传递的依然是值,只是这个值是一个对象的引用地址的副本。实参user存储的是User对象在堆内存中的地址,调用changeUser方法时,把这个地址值复制了一份给形参param,此时user和param都指向同一个User对象,所以修改param指向的对象的属性时,user指向的对象也会变化。
我们再做一个测试,在方法内修改形参的引用指向:
public class ReferencePassTest2 {
public static void main(String[] args) {
User user = new User("张三", 18);
System.out.println("修改前user的name:" + user.name);
changeUserReference(user);
System.out.println("修改后user的name:" + user.name);
}
private static void changeUserReference(User param) {
param = new User("李四", 20);
System.out.println("方法内param的name:" + param.name);
}
}
运行结果如下:
修改前user的name:张三 方法内param的name:李四 修改后user的name:张三
可以看到,我们在方法内让param指向了一个新的User对象,但是实参user的指向并没有发生变化,这恰恰证明了Java是值传递:传递的是引用地址的副本,修改这个副本的指向不会影响原来的实参的指向。
总结
Java中方法的参数传递始终是值传递,无论是基本数据类型还是引用数据类型,传递的都是实参的副本:
- 基本数据类型传递的是值的副本,修改形参不会影响实参。
- 引用数据类型传递的是对象引用地址的副本,修改形参指向的对象的属性会影响实参指向的对象,但是修改形参的引用指向不会影响实参的引用指向。
只要记住传递的是副本这个核心点,就能清晰区分值传递和其他传递机制的差异,避免开发中出现相关逻辑错误。