按值调用(call by value)表示方法接收的是调用者提供的值。
按引用调用(call by reference)表示方法接收的是调用者提供的变量地址。
一个方法可以修改传递引用所对应的变量值,而不能修改传递值调用所对应的变量值。
Java总是采用按值调用,方法得到的是所有参数值的一个拷贝,方法不能修改传递给它的任何参数变量的内容。
eg.
public static void change(int x){
x++;
System.out.println("x = "+x);
}
public static void main(String[] args) {
int a = 1;
change(a);
System.out.println("a = "+a);
}
上面代码执行后,输出的结果如下
看一下具体的执行过程:
1.x被初始化为a的一个拷贝,也就是1;
2.x执行x++后等于2,此时a依旧是1;
3.方法结束后,参数变量x不再使用。
方法参数共有两种类型:基本数据类型和对象引用。已经看到,一个方法不能修改基本数据类型的参数,而对象引用作为参数就不同了,看下面的例子
先建一个学生类,简单的有姓名和年龄两个属性。
public class Student {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
}
利用下面方法实现年龄增长
public static void change(Student a){
a.setAge(a.getAge()+1);
System.out.println(a.getName()+"'s age is "+a.getAge());
}
public static void main(String[] args) {
Student stu = new Student("Stan",9);
System.out.println(stu.getName()+"'s age is "+stu.getAge());
change(stu);
System.out.println(stu.getName()+"'s age is "+stu.getAge());
}
上面代码执行后,输出的结果如下
已经看到,实现一个改变对象参数状态的方法并不是一件难事,理由很简单,方法得到的是对象引用的拷贝,对象引用及其拷贝同时引用一个对象。
看一下具体的执行过程:
1.a被初始化为stu值的拷贝,这里是对象的引用;
2.change方法应用于这个对象的引用,stu和a同时引用的那个Student对象的年龄+1;
3.方法结束后,参数变量a不再使用,而变量对象stu继续引用那个年龄+1的学生对象。
回到最初的起点,很多程序设计语言提供了两种参数传递的方式,就是文章开头提到的按值调用和按引用调用,看到这里可能大家认为Java对对象采用的是按引用调用,实际上这种理解是错误的,文章开头已经有了说明Java总是采用按值调用,方法得到的是所有参数值的一个拷贝,方法不能修改传递给它的任何参数变量的内容。
下面举一个反例来阐述这个问题。
同样是Student类,现在写一个交换学生的方法。
public static void change(Student a,Student b){
Student temp = a;
a = b;
b = temp;
System.out.println("a's name is "+a.getName());
System.out.println("b's name is "+b.getName());
}
public static void main(String[] args) {
Student stu1 = new Student("Stan",9);
Student stu2 = new Student("Kyle",9);
System.out.println(stu1.getName()+"'s age is "+stu1.getAge());
System.out.println(stu2.getName()+"'s age is "+stu2.getAge());
change(stu1,stu2);
System.out.println(stu1.getName()+"'s age is "+stu1.getAge());
System.out.println(stu2.getName()+"'s age is "+stu2.getAge());
}
如果Java程序设计语言对对象调用采用的是按引用调用,那么这个方法就应该能实现交换数据的效果,stu1变成Kyle而stu1变成Stan。
但是让我们看看执行结果
方法并没有改变存储在变量stu1和stu2中的对象的引用。change方法的参数a和b被初始化为两个对象引用的拷贝,这个方法交换的是这两个拷贝,即a和b的引用发生了改变,相互引用了对方的对象,但stu1和stu2没有改变,没有对stu1和stu2产生影响。
最终,在方法结束时参数变量a和b被废弃了,原来的变量stu1和stu2依然引用这个方法调用之前所引用的对象。
这个过程说明,Java程序设计语言对对象采用的不是按引用调用,实际上,对象引用进行的是值传递。即把引用的值传递进去赋值给参数,产生一个新的引用。
下面是总结:
1.一个方法不能修改一个基本数据类型的参数;
2.一个方法可以改变一个对象参数的状态;
3.一个方法不能让对象参数引用一个新的对象从而传递出来。