Java是按值调用还是按引用调用?
先说结论,Java总是采用按值调用
1.按值调用和按引用调用
我们首先明确两个概念- 按值调用:表示方法接受的是调用者提供的值
- 按引用调用:表示方法接受的是调用者提供的变量地址
而按引用调用这是直接将参数的变量地址给了方法,也就是说方法可以直接修改参数的值
接下来我们从下面两个角度来看java的按值调用
- 基本数据类型
- 对象引用
2.基本数据类型的按值调用
我们来看下面这样一个程序class test{
public static void main(String[] args) {
int x = 5;
int y = 10;
swap(x, y);
System.out.println("----------------");
System.out.println("在main方法中x的值为:" + x);
System.out.println("在main方法中y的值为:" + y);
}
public static void swap(int x, int y){
int temp = x;
x = y;
y = temp;
System.out.println("在swap方法中x的值为:" + x);
System.out.println("在swap方法中y的值为:" + y);
}
}
输出结果:
在swap方法中x的值为:10
在swap方法中y的值为:5
----------------
在main方法中x的值为:5
在main方法中y的值为:10
分析:我们不难看出,通过调用swap函数交换x和y的值在swap函数内成功了,但是在main函数中x和y依然保持原来的值。传入swap函数的参数x和y实际上是main函数中x和y的副本,main函数中的x和传入swap方法的变量x具有相同的值,但是在内存中的位置不同,因此对swap方法中的变量x的操作,并不会对main函数中的x造成影响,变量y也同理,由此可知java在基本数据类型上采用按值调用
3.对象引用的按值调用
我们看下面这个程序class Student{
String name;
public Student(){
}
public Student(String name){
this.name = name;
}
}
class test{
public static void main(String[] args) {
var s1 = new Student("张三");
var s2 = new Student("李四");
swap(s1, s2);
System.out.println("在调用swap方法后,main方法中变量s1的名字为:" + s1.name);
System.out.println("在调用swap方法后,main方法中变量s2的名字为:" + s2.name);
}
public static void swap(Student a, Student b){
Student temp = a;
a = b;
b = temp;
System.out.println("在swap方法中变量a(s1的副本)的名字为:" + a.name);
System.out.println("在swap方法中变量b(s2的副本)的名字为:" + b.name);
}
}
输出结果:
在swap方法中变量a(s1的副本)的名字为:李四
在swap方法中变量b(s2的副本)的名字为:张三
在调用swap方法后,main方法中变量s1的名字为:张三
在调用swap方法后,main方法中变量s2的名字为:李四
我们来一步一步看一下这个过程:
(1)最开始,swap方法会初始两个student变量a,b,此时还没有引用任何对象看
当调用swap方法的时候,a和s1引用同一个Student对象,b和s2引用同一个Student对象
public static void swap(Student a, Student b)
(2)在swap函数内,
Student temp = a;
创建了一个Student的变量temp,并初始化其引用对象为a所引用的对象
(3)在swap函数内将a,b进行转换
a=b
这是将a的引用的对象变成了b所引用的对象
(4)在swap函数内部,
b = temp;
将b所引用的对象变成了temp所引用的对象
到这儿,我们可以发现,我们一直都是在操作s1和s2的副本a、b,s1和s2所引用的对象并没有发生改变,这就说明了java对象引用是按值调用的。