1 代码示例
首先查看如下代码,在main方法中新建int、String变量和int[]数据,以及一个person对象,在pass方法中进行修改,然后在回到main方法中进行打印,打印的结果以及注释在代码里面,结果是int变量和String变量没有修改,int[]数组和Person对象有修改。所以就引出今天要讨论的问题,Java是值传递还引用传递?
1 | import java.util.Arrays; |
2 值传递和引用传递的定义
要讨论这个问题,我们先了解什么是值传递?是什么是引用传递?
值传递:指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
引用传递:是指在调用函数时将实际参数的地址直接传递到函数中(的形参),那么在函数中对参数所进行的修改,将影响到实际参数。
3 基本数据类和引用数据类型
Java语言中的数据类型,可以分为基本数据类型和引用数据类型:
基本数据类型和引用类型定义
基本数据类:Java 中有八种基本数据类型“byte、short、int、long、float、double、char、boolean”
引用类型:类、数组和接口
基本数据类型和引用类型在内存中的存储方式
基本数据类型:存放在栈内存中,用完就消失。
引用类型:在栈内存中存放引用堆内存的地址,在堆内存中存储类、对象、数组等。当没用引用指向堆内存中的类、对象、数组时,由 GC回收机制不定期自动清理。
基本类型、引用类型内存简单说明图
关于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,然后将数组的地址放回给虚拟机栈中的arrPerson 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里面也可以看出:
当执行完pass方法后,pass方法出栈,这时main方法中的a和str并没有改变,但是arr和person所指向的两个对象在堆中已经发生了改变。
5 总结
无论是基本类型和是引用类型,在实参传入形参时,都是值传递,也就是说传递的都是一个副本,而不是内容本身,所以Java是值传递。
参考:https://blog.csdn.net/xu892278564/article/details/86217752