值传递与引用传递
2024-09-18 02:46:04 # Technical # JavaBase

值传递(Call by value):在参数传递过程中,形参和实参占用了两个完全不同的内存空间。形参所存储的内容是实参存储内容的一份拷贝。实际上,Java对象的传递就符合这个定义,只不过形参和实参所储存的内容并不是常规意义上的变量值,而是变量的地址

引用传递(Call by Reference):在参数传递的过程中,形参和实参完全是同一块内存空间,两者不分彼此。 实际上,形参名和实参名只是编程中的不同符号,在程序运行过程中,内存中存储的空间才是最重要的。不同的变量名并不能说明占用的内存存储空间不同

所以值传递与引用传递的本质 不在与传递的是值还是地址(况且地址也是个值),而在于形参与实参是否占用同一块内存空间

那么 形参实参 又是什么?

形参:定义函数名和函数体的时候使用的参数,目的是用来接收调用该函数时传入的参数

实参:调用有参函数时,主调函数和被调函数之间有数据传递关系。在主调函数中调用一个函数时,函数名后面括号中的参数称为「实参」

1
2
3
4
5
6
7
8
public static void main(String[] args) {
String hi = "hello world";
sayHi(hi); // 实参 hi
}

public static void sayHi(String hi) { // 形参 hi
System.out.println(hi);
}

Round 1

1
2
3
4
5
6
7
8
9
10
public static void main(String[] args) {
int i = 1;
m1(i);
System.out.println("main: " + i);
}

public static void m1(int i) {
i = 10;
System.out.println("m1: " + i);
}

Round 2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public static void main(String[] args) {
User user = new User();
user.age = 1;
m2(user);
System.out.println("main: " + user);
}

public static void m2(User user) {
user.age = 2;
System.out.println("m2: " + user);
}

static class User {
int age;

@Override
public String toString() {
return "User{" +
"age=" + age +
'}';
}
}

Round 3

1
2
3
4
5
6
7
8
9
10
public static void main(String[] args) {
String str = "111";
m3(str);
System.out.println("main: " + str);
}

public static void m3(String str) {
str = "abc";
System.out.println(str);
}

Round 4

1
2
3
4
5
6
7
8
9
10
11
12
13
public static void main(String[] args) {
String s1 = "111";
String s2 = "222";
m4(s1, s2);
System.out.println("main s1: " + s1 + " s2: " + s2);
}

public static void m4(String s1, String s2) {
String temp = s1;
s1 = s2;
s2 = temp;
System.out.println("m4 s1: " + s1 + " s2: " + s2);
}

说明

实参与形参

传递给方法的只是实参的内存地址,上面的 Round1、Round2 和 Round4 相当于图中的 M1,它们都只是改变的形参的内存地址,并没有对实参产生任何影响,而 Round3 相当于图中的 M2,形参通过内存地址访问到 Object4 对象,修改了 Object4 的属性,这个「影响」会「同步」到实参,因为它们都是指向同一内存地址