让我们回顾一下计算机科学术语,这些术语描述了如何以编程语言将参数传递给方法(或函数)。
术语“按值调用”表示方法仅获得调用者提供的值。
相反, 按引用调用意味着该方法获取调用者提供的变量的 位置。因此,一种方法可以 修改存储在按引用传递的变量中的值,但不能修改按值传递的变量中存储的值。这些“按......调用”(call by) 术语是标准的计算机科学术语,用于描述各种编程语言(而不仅仅是Java)中方法参数的行为。
Java编程语言 始终使用按值调用。这意味着该方法将获取所有参数值的副本。特别是,该方法无法修改传递给它的任何参数变量的内容。
例如,考虑以下调用:
double percent = 10;
harry.raiseSalary(percent);
无论方法如何实现,我们都知道在方法调用之后,percent的值仍为10。
让我们更仔细地研究这种情况。假设一个方法试图将方法参数的值增加三倍:
public static void tripleValue(double x) // doesn't work
{
x = 3 * x;
}
然后调用此方法:
double percent = 10;
tripleValue(percent);
但是,这不起作用。在方法调用之后,percent的值仍为10。这是发生的情况:
1。
x使用percent(即10)值的副本进行初始化。
2。
x增加了三倍,现在是30。但是percent仍然是10(见图4.6)。
3。
该方法结束,并且不再使用参数变量x。
但是,有两种方法参数:
•基本类型(数字,布尔值)
•对象引用
您已经看到,方法无法更改基本类型参数。对象参数的情况有所不同。您可以轻松地实现将员工的工资增加三倍的方法:
public static void TripleSalary(Employee x)//起作用
{
x.raiseSalary(200);
}
当你调用时:
harry = new Employee(. . .);
tripleSalary(harry);
然后会发生以下情况:
1。
x使用harry值的副本(即对象引用)初始化。
2。
raiseSalary方法将应用于该对象引用。x和harry都引用的Employee对象的薪水提高了200%。
3。
该方法结束,并且不再使用参数变量x。当然,对象变量harry继续引用其薪水增加了三倍的对象(请参见图4.7)。
如您所见,很容易(实际上很常见)实现更改对象参数状态的方法。原因很简单。
该方法获取对象引用的副本,原始副本和副本都引用同一对象。
许多编程语言(特别是C ++和Pascal)具有两种参数传递机制:按值调用和按引用调用。一些程序员(甚至不幸的是,甚至有些书的作者)声称Java对对象使用了按引用调用。那是错误的。由于这是一种常见的误解,因此值得详细研究一个反例。
让我们尝试编写一个交换两个Employee对象的方法:
public static void swap(Employee x, Employee y) // doesn't work
{
Employee temp = x;
x = y;
y = temp;
}
如果Java使用对对象的引用调用,则此方法将起作用:
var a = new Employee("Alice", . . .);
var b = new Employee("Bob", . . .);
swap(a, b);
// does a now refer to Bob, b to Alice?
但是,该方法实际上并没有更改存储在变量a和b中的对象引用。swap方法的x和y参数使用这些引用的副本进行初始化 。然后该方法继续交换这些副本。
// x refers to Alice, y to Bob
Employee temp = x;
x = y;
y = temp;
// now x refers to Bob, y to Alice
但是最终,这是无效的。该方法结束时,将放弃参数变量x和y。原始变量a和b仍然引用与方法调用之前相同的对象。
这表明Java编程语言不对对象使用按引用调用。而是, 对象引用按值传递。
以下是Java中方法参数可以做什么和不能做什么的摘要:
•方法不能修改原始类型的参数(即数字或布尔值)。
•方法可以更改对象参数的 状态。
•方法不能使对象参数引用新对象。
C ++注意: C ++同时具有按值调用和按引用调用的功能。您可以用&标记参考参数。例如,您可以轻松实现修改其引用参数的方法void TripleValue(double&x)或void swap(Employee&x,Employee&y)。