通过一段代码来引入今天的主题:猜一下下面这段代码的执行结果是什么?
public class Test {
public static void swap1(int a,int b){
int temp=a;
a=b;
b=temp;
System.out.println("函数中:a:"+a+" b:"+b);
}
public static void main(String[] args) {
int a=10;
int b=20;
swap1(a,b);
System.out.println("主方法:a:"+a+" b:"+b);
}
}
结果为:
发现两个变量经过一个函数调用交换之后,他们的值并没有发生改变,通过这段代码,我们认为只是把这两个变量(实参)拷贝了一份传递到函数中的形参中,并没有改变这两个变量原本的值;这种方式是值传递;
但是观察下面这段代码,会发现:
public class ParamTest {
public static void swap2(int[] array){
int temp=array[0];
array[0]=array[1];
array[1]=temp;
System.out.print("函数中:");
for(int i=0;i<array.length;i++){
System.out.print(array[i]+" ");
}
System.out.println();
}
public static void main(String[] args) {
int[] array=new int[]{1,2};
swap2(array);
System.out.print("主方法中:");
for(int i=0;i<array.length;i++){
System.out.print(array[i]+" ");
}
}
}
结果为:
经过函数调用后,原始值竟然发生了改变,如果Java传参是值传递的话,那经过函数调用之后,他们的值不是应该没发生改变吗?这是为什么呢?Java传参不是值传递吗?为什么会产生和上面不一样的结果呢?
首先,我们要搞清楚值传递和引用传递的根本含义:
值传递:是指在调用函数时,把实际参数的值拷贝一份传递给形式参数;在函数调用时,是对形参进行一系类操作,改变的是形参的值,实参的值并不会发生改变;
引用传递:是指在调用函数时,将实际参数的地址传递给形式参数;在函数调用中,如果该地址指向的内容发生了变化,则实参的引用指向的值也会发生变化;
Java中数据的存储:
基本数据类型(八大基本数据类型)是存储在栈内存中;
引用数据类型(如数组、对象)是存储在栈内存中,而引用的对象的属性值是存储在堆内存中;使用new关键字创建出来的类型都是引用数据类型;
基本数据类型:
比如:int a=10;将a的值直接存储在栈中;
引用对象类型:
int[] array=new int[]{1,2};将array数组的地址存放在栈中,然后根据该地址去堆中查找该数组的值;
而Java中函数传参,确实是值传递,这个值传递,传递的是栈内存中的值;
对于基本数据类型,函数调用时:
将栈中的值(实参的值)复制了一份,赋值给形参,在函数中做的一系列变化,都是针对形参,并不影响实参的值;
对于引用数据类型,函数调用时:
也是将栈中的值(即地址,因为引用类型的地址是存放在栈中的)复制了一份,赋值给形参,所以形参和实参的地址是一样的,他们指向的是堆中的同一段内存,所以当在函数中,对形参进行一系列操作(比如重新赋值)时,如果形参指向的内存的内容发生了变化,则实参指向的内容也会发生变化(因为形参和实参的地址一样,它们指向堆中同一段内存);
所以,Java中函数调用时是值传递,只是传递的值是栈中的值,对于基本数据类型,栈中存储的值就是变量额值;而对于引用数据类型,栈中存储的值是该引用变量的地址;