using System;
namespace ConsoleIdeaTest
{
internal class Program
{
static void Main(string[] args)
{
//A.值参数传递
int x = 100;
Calculator.Calculate(x); //120
Console.WriteLine("主函数中:\n哈希代码:{0}\n变量的值:{1}\n", x.GetHashCode(), x); //100;传值参数是复制x的副本到方法中操作,输出的x的值不会影响主函数中x的值
Console.WriteLine("==========================");
//B.引用参数传递并在方法1中为引用创建新实例(少见)
Student stu = new Student() { Name = "Jerry" }; //先在主函数中创建了引用变量stu和实例new student
Anmethod1(stu);
Console.WriteLine("主函数中:\n哈希代码:{0}\n变量的值:{1}\n", stu.Name.GetHashCode(), stu.Name);
Console.WriteLine("==========================");
//观察可以发现传引用参数的时候打印出的Name不一样;但即使一样,也可以根据不同的哈希代码来确定这是两个不同的对象
//传引用参数,在将变量传入方法后,新创建了实例,内存上就又给新实例在堆上分配了一块新区域;
//C.引用参数传递但未在方法2中新建实例
Anmethod2(stu);
Console.WriteLine("主函数中:\nStu哈希代码:{0}\nStu变量的值:{1}\n", stu.Name.GetHashCode(), stu.Name);
}
static void Anmethod1(Student stu)
{
//B.传递引用参数调用的方法1
stu = new Student() { Name = "Tom" }; //引用变量stu传入方法后,重新创建了一个新的实例new student
Console.WriteLine("方法1中:\n哈希代码:{0}\n变量的值:{1}\n", stu.Name.GetHashCode(),stu.Name);
}
static void Anmethod2(Student stu)
{
//C.传递引用参数调用的方法2
stu.Name = "Tom"; //引用变量stu传入方法后,相当于在栈上创建了一个新的引用变量,也指向主函数中的同一个实例
Console.WriteLine("方法2中:\n哈希代码:{0}\n变量的值:{1}\n", stu.Name.GetHashCode(), stu.Name);
}
}
class Calculator
{
public static void Calculate(int x)
{
//A.传值参数调用的方法
x = x + 20;
Console.WriteLine("方法中:\n哈希代码:{0}\n变量的值:{1}\n", x.GetHashCode(), x);
}
}
class Student
{
//给类添加的属性,用来让上方主函数的实例可以访问Name属性
public string Name { get; set; }
}
}
一、值参数:
1、值类型:
值类型的值参数,方法调用时在栈上创建副本,方法内计算修改的均为该副本,不会影响原本栈上的值参数。
2、引用类型
引用类型的值参数,分以下两种情况:
①:引用类型的值参数在方法内新建了实例。这种情况下系统先给方法内的引用类型值参数在栈上分配内存空间,然后再给新实例在堆上分配新的内存空间,该引用类型的值参数会指向新实例在堆上的内存地址,后续的修改均为对新实例修改,不影响原引用类型值参数和对应的实例;
②:引用类型的值参数在方法内未新建实例。这种情况下系统先给方法内的引用类型值参数在栈上分配内存空间,然后引用类型值参数也指向原实例在堆内存中的地址,后续的修改会直接改变原实例的值(两个小朋友拉着同一个气球)。
3、特例string
string本身是引用类型,但字符串具有不可变性。
不可变性:当你给一个字符串重新赋值之后,老值并没有在内存中销毁,而是重新开辟一块空间存储新值。
当引用变量的值的类型是string时,如果后续要为该实例赋予新的字符串值,内存会在堆上为新值开辟空间,而不是直接覆盖旧值(所以如果短时间内大量重复为同一实例赋不同的字符串值,容易浪费内存);同时,相同字符串值的实例,他们的引用变量指向同一个该字符串的内存地址。