写在开头
简单粗暴点,开头直接呈上答案:在Java 中参数的传递总是采用“值传递”的方式。
解释一下什么是“值传递”和“引用传递”:
- 值传递(call by value):表示方法接收的是调用者提供的值。
- 引用传递(call by reference):表示方法接收的是调用者提供的变量地址。
也就是说,在Java中方法得到的是所有参数值的一个拷贝,方法并不能修改传递给它的任何参数变量的内容 。
乍一看有点懵,接下来我将用下面三个例子来阐述。也可以直接去看最后的结论
1、修改基本类型参数
先看下面这段代码片段
//定义一个方法,试图将传进来的参数值增加至2倍
public static void doubleValue(int value) {
value = 2 * value;
}
//调用这个方法并输出
public static void main(String[] args) {
int i = 1;
doubleValue(i);
System.out.println("i=" + i);
}
这是一个简单的例子,输出的结果显而易见,这个方法并不能将变量 i 从 1 修改成 2 。
下面我们来看看这个例子的具体过程:
- value 被初始化为 i 值的一个拷贝(value → 1);
- value 在方法体中被乘以 2 (value → 2),但此时 i 还是 1 ;
- 方法结束,value不再被使用(
value),控制台输出" i = 1"。
因此可以得到结论:一个方法不能修改一个基本数据类型的参数。
2、修改引用类型参数
先定义一个雇员类
public class Employee {
private int salary;//薪资
public Employee(int salary) {
this.salary = salary;
}
//省略getter和setter
}
然后创建一个对象,并尝试修改它的状态
//定义一个方法,试图将传进来的雇员对象的薪资提高至2倍
public static void doubleSalary(Employee employee) {
employee.setSalary(2*employee.getSalary());
}
//调用这个方法并输出
public static void main(String[] args) {
Employee tom = new Employee(100);
doubleSalary(tom);
System.out.println(tom.getSalary());
}
控制台输出结果为 200
由此可见,我们很容易的通过一个方法修改了传入的对象的状态
下面我们来看看具体执行过程:
- employee 被初始化为 tom 值的拷贝,它们同时引用同一个对象。
- doubleSalary 方法应用于这个对象引用,使这个对象的salary属性被修改为2倍。
- 方法结束后,参数 employee 不再使用,但变量 tom 仍然引用那个已经被修改salary属性的对象
因此可以得到结论:一个方法可以修改一个引用类型的参数的状态。
这个例子看起来似乎是Java对对象采用了引用调用?
然!
并!
不!
下面再给出一个反例来阐述这个问题。
3、交换两个引用类型参数的引用
首先我们来定义一个交换两个雇员对象的方法
public static void swap(Employee emp1,Employee emp2) {
Employee tmp = emp1;
emp1 = emp2;
emp2 = tmp;
}
然后创建两个对象 tom 和 bob,薪水分别为 100 和 200,调用交换方法并输出
public static void main(String[] args) {
Employee tom = new Employee(100);
Employee bob = new Employee(200);
swap(tom,bob);
System.out.println("tom's salary = " + tom.getSalary());
System.out.println("bob's salary = " + bob.getSalary());
}
如果 Java 对对象采用的是引用传递,那么这个方法就应该能够实现交换薪资的效果。
然而,控制台输出的结果为
tom’s salary = 100
bob’s salary = 200
可见,这个方法并没有奏效,tom 和 bob 仍然各自引用之前的对象。
我们来看一下具体的执行过程:
- emp1 被初始化为 tom 的拷贝,emp2 被初始化为 bob 的拷贝。
- swap方法应用于 emp1 和 emp2,使它们相互交换对象。(这里用交叉线来画比较易懂,但是这个Mermaid图我还不太会用,写出来就是下面这样了。推荐大家自己在纸上画一画帮助理解。)
- 最终,方法结束,emp1 和 emp2 不再被使用,原来的 tom 和 bob 仍然各自引用之前所引用的对象。
因此可以得到结论:一个方法不能让对象参数引用一个新的对象。
同时也证明了: Java 对对象采用的不是引用传递。
结论
通过上面三个小栗子,我们可以得到三个小结论:
- 一个方法不能修改一个基本数据类型的参数
- 一个方法可以修改一个引用类型的参数的状态
- 一个方法不能让对象参数引用一个新的对象
同时,也得到了最终结论: Java 的参数传递是值传递。