在程序设计语言中,将参数传递给方法(函数)又三种方式:
- 按值调用(call by value)表示方法接收的是调用者提供的值。
- 按引用调用(call by reference)表示方法接收的是调用者提供的变量地址。
- 按名调用(call by name),Algol 使用的就是这种参数传递方式。
Java 程序设计语言总是采用按值调用。也就是说,方法得到的是所有参数值的一个拷贝,特别是,方法不能修改传递给它的任何参数变量的内容。
比如,现在有一个方法,将一个参数值提升三倍:
public static void tripleValue(double x) {
x = 3 * x;
}
调用这个方法:
double percent = 10;
tripleValue(percent);
System.out.println(percent); // 10
可见调用之后还是 10,并没有改变 percent
这个值。
我们可以描述这个过程:
tripleValue()
中的x
被初始化为percent
值得一个拷贝(10)。- 在方法中,
x
乘以 3 之后等于 30,但precent
没有改变。 - 方法结束,
x
被回收。
但是,方法参数有两种类型:
- 基本数据类型
- 对象引用
其中,对象引用比较复杂,因为在方法中,使用对象的修改器,可以改变对象的状态:
public static void tripleValue(Employee x) {
x.raiseSalary(200);
}
但 Employee
实例 harry 来调用 tripeSalary(harry)
时,是可以改变该实例的状态的,也就是 harry.salary 的薪资变成原来的三倍。理由很简单,因为方法中的 x
和 harry
都是指向同一个对象。
根据上述的例子,可能会对你产生方法参数传入对象引用时是 按引用调用 的错觉。请记住,Java 中只有按值传递。下面举一个反例:
public static void swap(Employee x, Employee y) {
Employee temp = x;
x = y;
y = temp;
}
如果来调用:
Employee a = new Employee("a", ...);
Employee b = new Employee("b", ...);
swap(a, b); // 并不会交换
上述调用 swap()
并不会交换传入的两个参数,这是因为 Java 是按值传递的原因。变量 x 和 y 都是来自 a 和 b 对象的拷贝。可以看成这样:
x = a;
y = b;
虽然,x 和 a 指向同一实例,但是如果 x = y
那么 x 和 a 将没有任何联系。而且当方法结束的时候,x 和 y 都会自动回收。a 和 b 还是指向之前的实例。值得注意的是,可以修改 a 和 b 中实例的状态(域)。
总结一下:
- 一个方法不能修改一个基本数据类型的参数(即数值型或布尔型)。
- 一个方法可以改变一个对象参数的状态。
- 一个方法不能让对象参数引用一个新的对象。