在程序设计语言中,将参数传递给方法(函数)又三种方式:

    • 按值调用(call by value)表示方法接收的是调用者提供的值
    • 按引用调用(call by reference)表示方法接收的是调用者提供的变量地址
    • 按名调用(call by name),Algol 使用的就是这种参数传递方式。

    Java 程序设计语言总是采用按值调用。也就是说,方法得到的是所有参数值的一个拷贝,特别是,方法不能修改传递给它的任何参数变量的内容。
    比如,现在有一个方法,将一个参数值提升三倍:

    1. public static void tripleValue(double x) {
    2. x = 3 * x;
    3. }

    调用这个方法:

    1. double percent = 10;
    2. tripleValue(percent);
    3. System.out.println(percent); // 10

    可见调用之后还是 10,并没有改变 percent 这个值。
    我们可以描述这个过程:

    1. tripleValue() 中的 x 被初始化为 percent 值得一个拷贝(10)。
    2. 在方法中,x 乘以 3 之后等于 30,但 precent 没有改变。
    3. 方法结束,x 被回收。

    但是,方法参数有两种类型:

    • 基本数据类型
    • 对象引用

    其中,对象引用比较复杂,因为在方法中,使用对象的修改器,可以改变对象的状态:

    1. public static void tripleValue(Employee x) {
    2. x.raiseSalary(200);
    3. }

    Employee 实例 harry 来调用 tripeSalary(harry) 时,是可以改变该实例的状态的,也就是 harry.salary 的薪资变成原来的三倍。理由很简单,因为方法中的 xharry 都是指向同一个对象。
    根据上述的例子,可能会对你产生方法参数传入对象引用时是 按引用调用 的错觉。请记住,Java 中只有按值传递。下面举一个反例:

    1. public static void swap(Employee x, Employee y) {
    2. Employee temp = x;
    3. x = y;
    4. y = temp;
    5. }

    如果来调用:

    1. Employee a = new Employee("a", ...);
    2. Employee b = new Employee("b", ...);
    3. swap(a, b); // 并不会交换

    上述调用 swap() 并不会交换传入的两个参数,这是因为 Java 是按值传递的原因。变量 x 和 y 都是来自 a 和 b 对象的拷贝。可以看成这样:

    1. x = a;
    2. y = b;

    虽然,x 和 a 指向同一实例,但是如果 x = y 那么 x 和 a 将没有任何联系。而且当方法结束的时候,x 和 y 都会自动回收。a 和 b 还是指向之前的实例。值得注意的是,可以修改 a 和 b 中实例的状态(域)。
    总结一下:

    • 一个方法不能修改一个基本数据类型的参数(即数值型或布尔型)。
    • 一个方法可以改变一个对象参数的状态
    • 一个方法不能让对象参数引用一个新的对象。