当你在调用方法时,系统会通过将实参的值复制到形参的方式,把数据传递给方法。系统会执行如下操作:
- 在栈中为形参分配空间。
- 将实参的值复制给形参。
下面以一段代码举例,并说明形参和实参在方法执行的不同阶段在内存中的存储位置:
class P1
{
public int v1 = 20; //字段数据保存在堆中
}
class P2
{
static void Method(P1 f1, int f2) //形参f1 和 f2
{
f1.v1 += 5;
f2 += 5;
}
static void Main()
{
P1 a1 = new P1();
int a2 = 10;
Method(a1, a2); //实参a1 和 a2
Console.Write("a1: " + a1.v1 + " a2: " + a2);
}
}
输出结果:
a1:25 a2:10
以下为详解:
从Main函数里面开始看。“P1 a1 = new P1();”这句中,“P1 a1”表示类P1的引用变量叫做“a1”,“new P1()”创建了类P1的一个实例,简言之就是,创建了类P1的实例,随后将实例复制给类变量。其内存结构是:
![](https://i-blog.csdnimg.cn/blog_migrate/e4c2990f567986174655df533c82f766.png)
接下来是“int a2 = 10;”,表示声明一个int类型的变量a2,此时内存结构:
接下来是“Method(a1, a2);”,表示调用Method方法,将引用类型a1、值类型a2作为实参传入Method方法,方法执行后,系统将实参的值复制给形参,并在栈中为形参(也就是f1,f2)分配空间:
![](https://i-blog.csdnimg.cn/blog_migrate/842f6a97f70d90ea54ed73cfda461aaa.png)
现在把目光放到Method方法内部,里面“f1.v1 += 5; f2 += 5;” ,表示给对象f1的字段(也就是类P1中的v1)加上5,和给值f2加上5。此时内存结构图变成如下:
![](https://i-blog.csdnimg.cn/blog_migrate/b2ef215aafdcdf1c6fd5480fbb7305d0.png)
当方法执行完毕后,形参会从栈中弹出,此时内存结构图如下:
可以看出,a1的值(也就是指向的数据的值)被方法的行为改变了,变成了25;a2的值没有被方法行为改变,还是10。
所以说,单纯在方法中通过修改值类型的形参,无法改变原值;而修改引用类型的形参,就可以改变其原值。