“按...调用”是一个标准的计算机科学术语,是用来描述各种程序设计语言中关于方法参数的传递方式的。通常有两大类调用方式:按值调用、按引用调用。按值调用(或称值传递)指的是——方法接收的是调用者提供的值;按引用调用(或称引用传递)指的是——方法接收的是调用者提供的变量地址。
值传递的特点:方法得到的是所有参数值的一个拷贝,且方法不能修改传递给自己的任何参数变量的内容。
众所周知,C/C++是有值传递和引用传递的,而Java语言是否也是如此呢?看了许多的博客和技术文章,有的说Java语言只有值传递,也有的说二者都有(对基本类型是值传递、对对象是引用传递),到底是什么情况呢,决定通过具体代码示例深入了解一下。
情形一:方法参数为基本数据类型情况
public class TestController {
public static void main(String[] args) {
int number = -5;
System.out.println("方法在调用之前number:" + number); //-5
TestController.abs(number);
System.out.println("方法在调用之后number:" + number); //-5
}
public static int abs(int n) {
n= 10; //方法尝试修改传入的参数变量
return Math.abs(n);
}
}
分析:abs()方法接收number参数前number的值为-5,abs()方法执行完毕后,number的值仍然为-5,也就是说方法并不会去改变参数变量的内容,是一种值传递。参数变量换成其他基本类型结果也是一样。因此,对于基本数据类型的参数都是值传递。
情形二:方法参数为引用数据类型情况
public class TestController {
public static void main(String[] args) {
Student stu = new Student("xxwei");
System.out.println("before---------->" + stu.getName()); //xxwei
System.out.println("before---------->" + stu); //Student@3b9a45b3
TestController.update(stu);
System.out.println("after---------->" + stu.getName()); //xxwei33
System.out.println("after---------->" + stu); //Student@3b9a45b3
}
private static void update(Student student) {
student.setName("xxwei33");
}
}
class Student implements Serializable {
public String name;
public Student() { }
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
'}';
}
}
分析:自定义了一个Student对象,main()方法中stu变量是指向Student对象的一个引用变量,通过update()方法执行前后的打印结果可以看出,该update()方法只是改变了对象的状态,并未将引用变量stu指向另一个对象(也就是说并未改变对象的地址,update()方法实际上接收的是一个拷贝的引用),所以对象类型不是引用调用,本质上对象的引用还是一种值传递。
情形三:举个反例,佐证一下情形二
public class TestController {
public static void main(String[] args) {
Student stu1 = new Student("Apple");
Student stu2 = new Student("Huawei");
System.out.println("stu1-----before------>" + stu1.getName()); //Apple
System.out.println("stu2-----before------>" + stu2.getName()); //Huawei
TestController.swap(stu1, stu2);
System.out.println("stu1-----after------>" + stu1.getName()); //Apple
System.out.println("stu2-----after------>" + stu2.getName()); //Huawei
}
private static void swap(Student m, Student n) {
Student temp = m;
m = n;
n = temp;
}
}
class Student implements Serializable {...}
分析:定义的swap()功能用于交换两个变量的位置,swap()方法中的m,n变量可以分别看作是stu1,stu2的引用拷贝,m,n变量的确实现了交换,但它们交换对象参数的结果却没有保留下来,打印后的结果中stu1仍然是Apple,也就是说stu1指向的仍然是原来的Student对象,而stu2仍然是Huawei,也就是说stu2指向的也仍然是原来的Student对象,没有实现真正的交换功能。因此,对象类型的参数不是引用调用,对象的引用是通过值进行传递的。
至此,通过这三个情形的例子分析后,可以明确了Java语言只有值传递类型。