首页 > 代码库 > 值类型与引用类型
值类型与引用类型
1.值类型
C#的值类型包括:结构体(数值类型、bool型、用户定义的结构体),枚举,可空类型。
Points是个结构体;给成员赋值有两种方式1.声明Points类型的对象,然后对象.成员分别赋值. 2.用new的方式初始化赋值,不会分配内存空间,此时要注意使用结构必须对每个成员进行赋值.但它是在栈空间中直接给成员分配内存,跟托管堆没有关系.
执行Points ps2=ps1,这里是把ps1对象复制赋值给ps2,在栈中把x,y成员的值复制了一份给ps2,是复制并传递过程的一个概念.执行ps1.x=30,ps1改的是自己对象成员的值;跟ps2中的成员没有关系,所以ps2.x输出的是ps1初始化时的值10;而ps2.y是改变后的值40.
1 static void Main(string[] args)//程序的入口方法 2 { 3 Points ps1; 4 ps1.x = 10; 5 ps1.y = 20; 6 Points ps2 = ps1; 7 ps1.x = 30; 8 ps2.y = 40; 9 }10 struct Points //定义了一个结构Points11 {12 public int x; //结构成员x13 public int y; //结构成员y14 }
2.引用类型
C#的引用类型包括:数组,用户定义的类、接口、委托,object,字符串。数组的元素,不管是引用类型还是值类型,都存储在托管堆上。引用类型在栈中存储一个引用,其实际的存储位置位于托管堆。
Pointc是一个类;new一个对象pc1并且给对象成员初始化x=10,y=20,此时在堆中给对象分配内存给x,y并且产生一个引用地.对象pc1通过引用地址指向x,y对象pc1;在栈中存的是引用地址.执行Pointc pc2=pc1代码是把pc1对象的引用地址复制一份给pc2,对象pc2通过地址指向堆内存中的x,y成员.执行pc1.x=30代码,对象pc1通过地址修改x的值,pc2的地址也是指向堆中的成员,所以输出的值也是30.执行pc2.y=40代码也是通过原来的地址修改y的值,所以对象pc1,pc2修改后的值都是x=30,y=40.
1 static void Main(string[] args) 2 { 3 MyPointc pc1 = new MyPointc(); 4 pc1.x = 10; 5 pc1.y = 20; 6 MyPointc pc2 = pc1; 7 pc1.x=30; 8 pc2.y=40; 9 }10 class MyPointc11 {12 public int x;13 public int y;14 }
值类型传参:
1 static void Main(string[] args) 3 { 5 Persons ps = new Persons(); 7 ps.state = "生病了"; 9 Docotr(ps);11 Console.WriteLine(ps.state);13 Console.ReadKey();15 }17 public static void Docotr(Persons p)19 {21 p.state = "病好了";23 }25 struct Persons27 {
29 public string state;31 }
结构Persons成员ps.state在栈在存放变量名,由于state是字符串所以存放的是堆中的引用地址,在堆中赋值分配空间。执行Docotr(ps);代码是把引用地址复制一份给Persons p
而指向原ps.state对象。当进入执行Docotr(Persons p)方法时,由于字符串不可改变性;在堆中会重新生成一个新的对象,从而p.state指向新的对象.
所以ps.state输出结果依然是“生病了
引用类型传参
1 static void Main(string[] args) 2 { 3 Personc pc = new Personc(); 4 pc.state = "生病了"; 5 Docotr(pc); 6 Console.WriteLine(pc.state); 7 Console.ReadKey(); 8 } 9 public static void Docotr( Personc p)10 {11 p.state = "病好了";12 }13 class Personc14 {15 public string state;16 }
Personc类new一个对象pc在栈中存放引用地址,在堆中pc.state赋值并分配内存空间。Pc通过地址指向堆中成员.执行代码Docotr(pc);是把对象pc引用地址复制一份给对象p,
通过引用地址修改pc.state=”病好了”所以修改后的输出为”病好了”
值类型与引用类型传参补充:
static void Main(string[] args) { Personc pc = new Personc(); pc.state = "生病了"; Docotr(pc.state); Console.WriteLine(pc.state); Console.ReadKey(); } public static void Docotr(string str) { str = "病好了"; } class Personc { public string state; }
引用类型复制的是地址,而数值类型复制的是值,但由于字符串的不可改变性,最终改变的都不是原来所指定的字符串对象,而是重新生成的新字符串,
所以对于引用类型还是数值类型来讲。用字符串参数传递都不会改变原字符串,所以上输出的结果为"生病了"。
值类型直接存储其值,变量本身就包含了其实例数据,而引用类型保存的只是实例数据的内存引用。因此,一个值类型变量就永远不会影响到其他的值类型变量,
而两个引用类型变量则很有可能指向同一地址,从而发生相互影响。
引用类型与值类型相同的是,结构体也可以实现接口;引用类型可以派生出新的类型,而值类型不能;引用类型可以包含null值,值类型不能;
引用类型变量的赋值只复制对象的引用,而不复制对象本身。而将一个值类型变量赋给另一个值类型变量时,将复制包含的值。