avatar

目录
Java是值传递还引用传递

1 代码示例

首先查看如下代码,在main方法中新建int、String变量和int[]数据,以及一个person对象,在pass方法中进行修改,然后在回到main方法中进行打印,打印的结果以及注释在代码里面,结果是int变量和String变量没有修改,int[]数组和Person对象有修改。所以就引出今天要讨论的问题,Java是值传递还引用传递?

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import java.util.Arrays;

public class PassDemo {
public static void main(String[] args) {
int a = 1;
String str = "main";
int[] arr = {1,2,3};
Person person = new Person("小王",20);

pass(a,str,arr,person);

System.out.println("a=" + a); // a=1
System.out.println("str=" + str); // str=main
System.out.println("arr = " + Arrays.toString(arr)); // arr = [-1, 2, 3]
System.out.println(person); // Person{name='老王', age=60}

}

private static void pass(int a, String str, int[] arr, Person person) {
a = 2; // 没有改变main函数中a的值
str = "pass"; // 没有改变main函数中str的值
arr[0] = -1; // 将main函数中arr={1,2,3}改成了arr={-1,2,3}

// 将main函数中Person{name='小王', age=20}改成了Person{name='老王', age=60}
person.setName("老王");
person.setAge(60);
}

}

class Person{
String name;
int age;
Person(String name, int age){
this.name = name;
this.age = age;
}

public void setName(String name) {
this.name = name;
}
public void setAge(int age){
this.age = age;
}

public String getName() {
return name;
}

public int getAge() {
return age;
}

@Override //////////////////////////xjkdjfkdj
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}

2 值传递和引用传递的定义

要讨论这个问题,我们先了解什么是值传递?是什么是引用传递?

值传递:指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。

引用传递:是指在调用函数时将实际参数的地址直接传递到函数中(的形参),那么在函数中对参数所进行的修改,将影响到实际参数。

3 基本数据类和引用数据类型

Java语言中的数据类型,可以分为基本数据类型和引用数据类型:

  1. 基本数据类型和引用类型定义

    基本数据类:Java 中有八种基本数据类型“byte、short、int、long、float、double、char、boolean”

    引用类型:类、数组和接口

  2. 基本数据类型和引用类型在内存中的存储方式

    基本数据类型:存放在栈内存中,用完就消失。

    引用类型:在栈内存中存放引用堆内存的地址,在堆内存中存储类、对象、数组等。当没用引用指向堆内存中的类、对象、数组时,由 GC回收机制不定期自动清理。

  3. 基本类型、引用类型内存简单说明图

关于Java中String类:String类是一个特殊的类,它属于引用数据类型。String内部类的value数组定义成了private final,因此是一个不可修改类,它不能像正常类对象一样直接修改,所以如果需要修改的时候,需要重新开辟空间赋值。但是在使用的过程中String看上去更像是基本数据类型,存的是常量池中的地址。

4 内存分析

首先是main函数的运行,在定义几个数据

  • int a = 1:int型数据a,栈中直接给a赋值为1。
  • String str = "main" :String类型数据str,相应于String str = new String("main");,首先会判断常量池中有没有“main”这个字符串,如果没有就会在常量池中新建这个字符串,然后将地址返回给虚拟机栈中的str。
  • int[] arr = {1,2,3} :int[]型数据arr,在堆中建立数组对象int[3],并且赋值1,2,3,然后将数组的地址放回给虚拟机栈中的arr
  • Person person = new Person(“小王”,20) :Person对象,同样在堆中建立对象,在常量池中新建常量,给name赋值为常量池中的地址,age初始化为20,然后对象地址返回给虚拟机栈中的person。

接着执行pass方法,执行过程如下:

  • a = 2:相当于在栈中新建一个变量a(与main方法里的同名),然后赋值为2。
  • `str = “pass” :在栈中新建一个字符串变量str(与main方法里的同名),同样在字符串常量池中判断是否有字符串”pass”,没有则新建一个,把地址返回给虚拟机栈中的str。
  • arr[0]= -1 :这里传给pass方法里的就是arr存在堆中的地址,所以修改的就是实际堆中的数据。
  • person.setName("老王")" 和"person.setName("老王") :和修改数组类似,同样是修改了堆中的数据。

在pass方法执行的过程中传入的形参a和str是没有使用过的,IDEA里面也可以看出:
image-20200721162307153

当执行完pass方法后,pass方法出栈,这时main方法中的a和str并没有改变,但是arr和person所指向的两个对象在堆中已经发生了改变。

5 总结

无论是基本类型和是引用类型,在实参传入形参时,都是值传递,也就是说传递的都是一个副本,而不是内容本身,所以Java是值传递。

参考:https://blog.csdn.net/xu892278564/article/details/86217752

文章作者: foochane
文章链接: https://foochane.cn/article/2020072101.html
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 foochane
打赏
  • 微信
    微信
  • 支付宝
    支付宝

评论