形参与实参的区别:
- 形参出现在函数定义中,在整个函数体内都可以使用, 离开该函数则不能使用。实参出现在主调函数中,进入被调函数后,实参变量也不能使用。(如下例 :pass(a,b);中的 a,b 就是实参,而 ax,bx 就是形参)
- 形参和实参的功能是作数据传送。发生函数调用时, 主调函数把实参的值传送给被调函数的形参从而实现主调函数向被调函数的数据传送。
- 形参变量只有在被调用时才分配内存单元,在调用结束时, 即刻释放所分配的内存单元。因此,形参只有在函数内部有效。 函数调用结束返回主调函数后则不能 再使用该形参变量。
- 实参可以是常量、变量、表达式、函数等, 无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值, 以便把这些值传送给形参。 因此应预先用赋值, 输入等办法使实参获得确定值。
- 实参和形参在数量上,类型上,顺序上应严格一致, 否则会发生“类型不匹配”的错误。
- 函数调用中发生的数据传送是单向的。 即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。 因此在函数调用过程中,形参的值发生改变, 而实参中的值不会变化。
在Java 中所有的参数传递都是按值传递,而不存在C++中的引用传递(在C++中使用 &)。
1.基本类型参数传递
先看一个例子:
package demo2;
public class ParaTest {
public static void main(String[] args) {
int a = 1;
int b = 2;
pass(a,b);
System.out.println("a的值:"+a);
System.out.println("b的值:"+b);
}
public static void pass(int ax,int bx){
//调用pass()方法时,相当于进行了以下操作
//ax = a;
//bx = b;
ax = 5;
bx = 10;
}
}
输出结果:
a的值:1
b的值:2
值赋给ax,b的值赋给bx。在调用完pass()方法后,ax,bx所占内存就会释放。而且ax,bx只能在pass()方法中使用,在外部不能使用。
我们无法通过形参的引用来改变实参。
2.引用类型参数传递
先来看一个例子:
1 package demo2;
2
3 public class ParaTest2 {
4
5 public static void main(String[] args) {
6 Demo de = new Demo(12); //de 为Demo对象的一个引用(句柄),指向对象真实的地址单元
7
8 System.out.println("调用pass方法前:");
9 System.out.println(de);
10 pass(de);
11
12 System.out.println("调用pass方法后:");
13 System.out.println(de);
14
15 }
16
17 public static void pass(Demo d){
18 d = new Demo(20); //新建了一个对象,并传入值20
19 System.out.println("调用pass方法中:");
20 System.out.println(d);
21 }
22
23 }
24 //Demo类
25 class Demo{
26
27 private int num;
28
29 //构造方法,给 num进行初始化操作
30 public Demo(int n){
31 num = n;
32 }
33
34 //重写了toString方法,返回内容
35 public String toString(){
36 return "num的值为:"+num;
37 }
38 }
输出结果如下:
调用pass方法前:
num的值为:12
调用pass方法中:
num的值为:20
调用pass方法后:
num的值为:12
分析:
我们定义了一个Demo类,并重写了Object类中继承的toString 方法,在pass()方法中的第18行,我们为形参d重新分配内存空间,并将num的值指定为20,然而并为改变
实参de的值,de中的num值仍为12,这说明引用的传递也是按值传递。
引用的赋值:存在A,B两个引用,如果 A = B(注意这里是将B赋值给A),那么A将指向B所指向的地址。
上述过程可以用下图表示:
de指向的地址不变,调用方法时,只是新建了对象,d指向新对象的地址
我们虽然不能通过形参的引用来改变实参,但我们可以改变形参引用所指向的对象内容,即改变所指对象中数据的值(对象内容)。
3.通过形参引用修改对象的值
代码与上十分相似,只需要在Demo类中加一个setNum方法:
public void setNum(int n){
num = n;
}
并将上例第18行改为:
d.setNum(20);
输出结果:
调用pass方法前:
num的值为:12
调用pass方法中:
num的值为:20
调用pass方法后:
num的值为:20
可见,可以通过形参的引用改变实参所指向的对象的内容。
注意:
1>数组作为参数传递时,上述情况对数组同样适用。(因为数组也是对象,数组的元素即对象的内容,通过形参的引用可改变数组的元素。)
2>String 作为参数传递,String是类,并不是基本数据类型,然而,String是非可变类,String对象一经创建,就无法修改,对String对象的一切操作结果都是
返回新创建的对象,而不是子啊原有对象上执行。
3>StringBuilder 和 StringBuffer 类是可变的。对其并非创建新的对象,而是直接在原有的对象上修改,所以形参对对象的改变也就直接影响到实参。
4>引用自身的改变与引用所指向的对象的改变是不同的,前者指的是引用指向了其他的地址空间,而后者是指通过引用改变了所指对象的数据(例如改变了对象成员变量的值)。