2.9.3 参数传递
一、值传递
在2.9.2中已经介绍了方法是如何定义并且被调用的,其中提到参数传递的过程,
关于参数传递,需要注意的问题还有很多,比如下面这个例子:
例2:
public class Test{
public static void add(int a){
a=a+1;
}
public static void main(String[] args){
int n=33;
add(n);
System.out.println("n="+n);
}
}
执行这个程序,会发现输出结果是“n=33”,而不是“n=34”。
实参n的值是33,确实被传递给了形参a,a的值加1应该变成34,为什么返回main方法后再输出n的值还是33?
这是因为这里所谓的“传递”,其实是个复制粘贴的过程,实参n的值被复制给了形参a,a的初始值与n一样,但是之后a的值再做任何改变,不会影响到原件n。
这种参数传递方式叫做值传递。
二、引用传递
我们再看这个例子:
例3:
public class Test{
public static void add(int[] a){
a[0]=a[0]+1;
}
public static void main(String[] args){
int[] n={33};
add(n);
System.out.println("n[0]="+n[0]);
}
}
这次输出的结果却是“n[0]=34”,为什么这次又加1了?
因为这次不是值传递,而是引用传递。
首先得说一下什么叫引用?前面介绍的变量,其实按照数据类型可以分为两大类,除了之前详细介绍过的基本数据类型,其实还有一个大类就是引用数据类型。这两大类之间的区别就是它们存储数据的方式。
1、基本数据类型的变量,值就直接存储在变量中,对这个变量赋新值,新值会直接覆盖原先的旧值。
2、引用数据类型的变量,如数组b,这个数组变量b中存储的其实是一个引用,可以理解为一个地址,指向内存的堆栈区中某一个位置
如果执行下面的代码,控制台输出的会是一个类似地址的十六进制数
int[] b= {11,22,33,44};
System.out.println(b);
创建数组b时,内存会在堆栈区中开辟一个16字节大小的空间(一个int型占4个字节,数组有4个元素,一共就是4*4=16个字节),依次存储数组b中4个元素的值。
当需要访问数组元素时,例如b[2],计算机会根据变量b中存储的地址找到b[0],再往下数两格就找到了b[2]。
这就是引用类型变量的存储方式,所以要注意,如果往引用类型变量中赋新值,到底是改变其所指向的内存中的数值,还是改变了这个变量中所存储的引用?
如果执行下面的代码,猜猜会输出什么?
int[] b= {11,22,33,44};
int[] c= {55,66};
System.out.println(b[0]);
b=c;
System.out.println(b[0]);
输出是:
11
55
再看这个:
int[] b= {11,22,33,44};
System.out.println(b[0]);
b[0]=88;
System.out.println(b[0]);
输出是:
11
88
一个是改变数组b的引用,使其重新指向数组c,两个数组指向内存中的同一片空间;一个是改变数组b中的第0个元素中存储的值,新值直接覆盖旧值,数组b本身的引用没有变。
理解了引用之后,我们再来看看方法的引用传递,在前面的例3中,实参n传递给形参a的其实是n中存储的引用,也就是说,n和a实际上指向了内存中的同一片空间。程序通过变量a的引用来访问数组中第0个元素的值,新值覆盖了旧值,当再通过变量n来访问数组中第0个元素时,获取的自然就是改变之后的新值。