程序设计语言中,参数传递主要包括两种,一种是值传递,也就是值调用,表示方法接收的是调用者提供的值;另一种是引用传递,也就是引用调用,表示方法接收的是调用者提供的变量地址。一个方法可以修改传递引用所对应的变量值,而不能修改传递值调用所对应的变量值。
java总是采用值调用。也就是说,方法得到的是所有参数值的一个拷贝,也就是说,方法不能修改传递给它的任何参数变量的内容。
方法参数包含两种类型:
>基本数据类型(数字,布尔值);
>对象引用。
下面首先看第一种情况的调用:
程序:
public class staticsd
{
public static void main(String[] args)
{
double value=10;
trapeValue(value);
System.out.println(value);
}
public static void trapeValue(double a)
{
a=a*3;
}
}
试图通过调用trapeValue方法使变量value增加3倍,但结果打印的value值仍然是10.
下面看一下具体的执行过程:
1)方法中的参数a初始化为value的一个拷贝;
2)a乘以3后变为30,但是value仍然是0;
3)这个方法结束后,参数a不再使用。
我们已经看到,一个方法不可能修改一个基本数据类型的参数。但是对象引用作为参数时,是不一样的。看一个例子:
public class staticsd
{
public static void main(String[] args)
{
Employee coder=new Employee(5000);
tripleSalary(coder);
System.out.println(coder.getSalary());
}
public static void tripleSalary(Employee x)
{
x.raiseSalary(200);
}
}
class Employee
{
private int salary;
public Employee(int salary) {
this.setSalary(salary);
}
public void raiseSalary(int percent)
{
setSalary(getSalary() + (getSalary()*percent/100));
}
public void setSalary(int salary) {
this.salary = salary;
}
public int getSalary() {
return salary;
}
}
具体的执行过程:
1)x被初始化为coder值的拷贝,这里是一个对象的引用;
2)raiseSalary方法应用于这个对象引用。x和coder同时引用的那个Employee对象的薪金提高了200%;
3)方法结束后,参数变量x不再使用。当然,对象变量coder继续引用那个薪金增至3倍的雇员对象。
能够很容易改变对象参数状态的原因是对象引用及其他的拷贝同时引用同一个对象。
于是可能很多人会认为java对对象采用的是引用调用,然而,实际上,这种理解是错误的。下面给出一个反例来详细阐述这个问题。
public class staticsd
{
public static void main(String[] args)
{
Employee artist=new Employee(1000,"Bob");
Employee actor=new Employee(100000,"Vivi");
swap(artist,actor);
System.out.println("after swap(), the artist is:"+artist.getName());
System.out.println("after swap(), the actor is:"+actor.getName());
}
public static void swap(Employee x,Employee y)
{
Employee temp=x;
x=y;
y=temp;
}
}
class Employee
{
private int salary;
private String name;
Employee(int salary,String name)
{
this.salary=salary;
this.name=name;
}
public void raiseSalary(int percent)
{
setSalary(getSalary() + (getSalary()*percent/100));
}
public void setSalary(int salary) {
this.salary = salary;
}
public int getSalary() {
return salary;
}
public String getName()
{
return name;
}
}
打印结果:
after swap(), the artist is:Bob
after swap(), the actor is:Vivi
显然,方法并没有改变存储在变量artist和b中的对象引用。swap方法交互的是两个拷贝x和y。这个过程说明:java对对象采用的不是引用调用,实际上,对象引用进行的是值传递。
最后给出一个演示以上情况的相应的程序:
/**
* This program demonstrates parameter passing in Java.
* @version 1.00 2000-01-27
* @author Cay Horstmann
*/
public class ParamTest
{
public static void main(String[] args)
{
/*
* Test 1: Methods can't modify numeric parameters
*/
System.out.println("Testing tripleValue:");
double percent = 10;
System.out.println("Before: percent=" + percent);
tripleValue(percent);
System.out.println("After: percent=" + percent);
/*
* Test 2: Methods can change the state of object parameters
*/
System.out.println("\nTesting tripleSalary:");
Employee harry = new Employee("Harry", 50000);
System.out.println("Before: salary=" + harry.getSalary());
tripleSalary(harry);
System.out.println("After: salary=" + harry.getSalary());
/*
* Test 3: Methods can't attach new objects to object parameters
*/
System.out.println("\nTesting swap:");
Employee a = new Employee("Alice", 70000);
Employee b = new Employee("Bob", 60000);
System.out.println("Before: a=" + a.getName());
System.out.println("Before: b=" + b.getName());
swap(a, b);
System.out.println("After: a=" + a.getName());
System.out.println("After: b=" + b.getName());
}
public static void tripleValue(double x) // doesn't work
{
x = 3 * x;
System.out.println("End of method: x=" + x);
}
public static void tripleSalary(Employee x) // works
{
x.raiseSalary(200);
System.out.println("End of method: salary=" + x.getSalary());
}
public static void swap(Employee x, Employee y)
{
Employee temp = x;
x = y;
y = temp;
System.out.println("End of method: x=" + x.getName());
System.out.println("End of method: y=" + y.getName());
}
}
class Employee // simplified Employee class
{
public Employee(String n, double s)
{
name = n;
salary = s;
}
public String getName()
{
return name;
}
public double getSalary()
{
return salary;
}
public void raiseSalary(double byPercent)
{
double raise = salary * byPercent / 100;
salary += raise;
}
private String name;
private double salary;
}