调用方法时,我需要传递实参给方法,在方法内部会改变这些实参的值。
在Java语言中,方法执行完毕后,这些实参的值会有变化吗。
先简单介绍一下什么是值传递,什么是引用传递
值传递:
> 调用方法时,传入的是实参的一个拷贝,原先的数据在方法结束后没有被改变
引用传递:
> 调用方法时,传入的是实参的地址,而不是拷贝,原先的数据会根据方法内容变化
> 注意:基本数据类型也是有地址的
Java是哪一种传递模式呢?
严格来说,Java只存在值传递,方法得到的是实参的拷贝,而不是变量的地址。
我们先搞清楚一些相关概念:
基本数据类型:都存储在栈上,不存在引用,直接保存数据值
引用数据类型:在jvm栈上保存堆上对象的地址,在堆内存上开辟一片空间,用于存放实体,即引用数据类型的具体信息
对于基本数据类型而言,方法调用过程如下:
* 在调用的方法的栈帧中初始化一个实参的副本;
* 对这个副本进行操作,原先main方法栈帧的变量的值不会发生变化;
* 并且这个方法执行完毕后,随着方法出栈,这个实参的副本也被销毁了
对于引用数据类型而言,方法调用过程如下:
* 在调用的方法的栈帧中声明一个引用的拷贝,因为是拷贝,所以这个引用中存的内存地址和原先的引用一样
* 结果就是,这个副本仍然指向了原先引用所指向的对象
* 对这个引用的副本进行操作,原先main方法栈帧的引用不会发生变化,但由于指向的是同一对象
* 结果就是,引用和引用拷贝指向的对象本身被改变了
* 方法结束后,这个引用拷贝也被销毁了
举例分析
下面是一个数组交换的demo,我们根据这个demo来分析一下,在传参过程中变量是怎么变化的:
public static void main(String[] args) {
int[] a = {20, 21, 22};
int[] b = {23, 24, 25};
System.out.println("============原始数组a/b==============");
System.out.print("数组a: ");
printArray(a);
System.out.print("数组b: ");
printArray(b);
System.out.println("==========swapArray方法中的数组==============");
swapArray(a, b);
System.out.println("==========swapArray后的数组a/b==============");
System.out.print("数组a: ");
printArray(a);
System.out.print("数组b: ");
printArray(b);
}
public static void swapArray(int[] arr1, int[] arr2) {
int[] tmp = arr1;
arr1 = arr2;
arr2 = tmp;
System.out.print("数组arr1: ");
printArray(arr1);
System.out.print("数组arr2: ");
printArray(arr2);
}
public static void printArray(int[] arr){
for (int i = 0; i < arr.length-1; i++) {
System.out.print(arr[i]+" , ");
}
System.out.println(arr[arr.length-1]);
}
程序输出
============原始数组a/b==============
数组a: 20 , 21 , 22
数组b: 23 , 24 , 25
==========swapArray方法中的数组==============
数组arr1: 23 , 24 , 25
数组arr2: 20 , 21 , 22
==========swapArray后的数组a/b==============
数组a: 20 , 21 , 22
数组b: 23 , 24 , 25
显然,main中的原始数组 a 和数组 b 经过swapArray方法后,值并没有改变
同时,方法中的数组确实交换成功了,可以看出来Java
程序运行过程内存分析
main方法先入栈在栈底,在堆上开辟两块连续的内存空间给引用数据类型变量 a 和 b,
swapArray方法再入栈,传入实参a,b,完成两个数组arr1 arr2 的交换
swapArray方法出栈,一旦出栈方法内的局部引用数据类型变量也销毁了,图中可以看出,main方法中的原数组仍然没有变化,说明再方法传参中,变量使用的是值传递,并没有改变原始数据
refering:
JavaGuide: 为什么Java中只有值传递?
王道训练营课件