首页 > 代码库 > 值类型与引用类型

值类型与引用类型

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         }

Personcnew一个对象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;          }
View Code

引用类型复制的是地址,而数值类型复制的是值,但由于字符串的不可改变性,最终改变的都不是原来所指定的字符串对象,而是重新生成的新字符串,

所以对于引用类型还是数值类型来讲。用字符串参数传递都不会改变原字符串,所以上输出的结果为"生病了"

值类型直接存储其值,变量本身就包含了其实例数据,而引用类型保存的只是实例数据的内存引用。因此,一个值类型变量就永远不会影响到其他的值类型变量,

而两个引用类型变量则很有可能指向同一地址,从而发生相互影响。

引用类型与值类型相同的是,结构体也可以实现接口;引用类型可以派生出新的类型,而值类型不能;引用类型可以包含null值,值类型不能;

引用类型变量的赋值只复制对象的引用,而不复制对象本身。而将一个值类型变量赋给另一个值类型变量时,将复制包含的值。