【C#基础】值类型和引用类型

来源:互联网 发布:php积分系统源码 编辑:程序博客网 时间:2024/05/16 09:51

一、前言:

    在备战软考的过程中,涉及到了原型模式,其中讲到了在浅复制的过程中,值类型和引用类型是有区别的。那么究竟什么是值类型,什么是引用类型呢?

在理解这两个概念之前,我们先谈一谈栈和堆。

    计算机的内存从概念上分,会有许许多多独立的块,堆和栈就是其中的两种内存块。是一种先进后出的数据结构,当我们调用一个方法时,假如这方法有参数的话,那么我们就需要在中为这个方法的参数方法所用到的变量局部变量)分配一小部分内存。当方法结束的时候,所占用的内存就会自动释放回栈中。堆是用于为类型实例(对象)分配空间的内存区域,当我们使用new创建一个对象的时候,new出来的东西放在中。更多详情,猛戳这里。


二、值类型和引用类型:

    C#的类型一共分为两类,一种是值类型(Value Type),一类是引用类型(Reference)。

                 

    每一种编程语言的值类型都有一些非常细小的不同,C#的内置值类型共有七种:int、long、float、char、bool、enum、struct。而string类型是一种具有值类型特性的特殊引用类型,且按下不表。

           

三、函数调用时参数的传递方式:

    1、传值调用是将实参传递给被调用函数的形参。因此实参既可以是表达式,也可以是变量(或数组元素)。

    2、传地址调用是将实参地址传给被调用函数的形参。所以,实参必须有地址。因此实参必须是变量(数组),不能表达式常量(因为他们不存在地址)。

    3、如果采用传值方式调用,则形参值的变化不会影响实参。

    4、如果采用引用方式调用,则形参值的变化直接反映到实参。


四、举例:

    基于值类型的变量直接包含值。将一个值类型变量赋给另一个值类型变量时,将复制包含的值。举个例子:int  a =10; int b = a,此时b的值为10,当把a付给b时,开辟一块新的空间来保存b的值,b的值为10。当把a的值该为50时,会在a的空间保存50.。与b无关,此时b仍为10。                                                                              

而引用类型则与之不同,因为引用类型指向的是同一个地址。  


原型模式例子:

简历类:

<span style="font-family:KaiTi_GB2312;font-size:24px;">class Resume:ICloneable{     private string name;     private string sex;     private string age;     private string timeArea;     private string company;   public Resume(string name)   {      this.name = name;   }//设置个人信息:public void SetPersonalInfo(string sex,string age)   {      this.sex = sex;      this.age = age;   }//设置工作经历public void SetWorkExperience(string sex,string age) {       this.timeArea = timeArea;       this.company = company;  }//显示public void Display() {     Console.WriteLine("{0} {1} {2}",name, sex, age);     Console.WriteLine("工作经历:{0} {1}",timeArea, company);  }  public Object Clone()   {       return (Object)this.MemberwiseClone();    }}</span>
客户端调用代码:

<span style="font-family:KaiTi_GB2312;font-size:24px;">static void Main(string[] args){   Resume a = new Resume("大鸟");   a.SetPersonalInfo("男","29");   a.SetWorkExperience("1998-2000","XX公司")   Resume b = (Resume)a.Clone();   b.setWorkExperience("1998-2006","YY企业")   Resume c = (Resume)a.Clone();   c.SetPersonalInfo("男","24");   a.Display();        b.Display();   c.Display();    Console.Read();}</span>


结果显示:
大鸟 男 29
工作经历  1998-2000  XX公司

大鸟 男 29
工作经历  1998-2006  YY公司

大鸟 男 24
工作经历  1998-2000  XX公司


工作经历类

<span style="font-family:KaiTi_GB2312;font-size:24px;"><span style="color:#ff6666;"><span style="color:#ff0000;">Class WorkExperience{    private string workDate;    public string WorkDate    {get {return workDate;}        set {workDate = value;}     }    private string company;    public string Company    {        get {return company;}        set {company = value;}     }}</span></span></span>


简历类:

<span style="font-family:KaiTi_GB2312;font-size:24px;">class Resume:ICloneable{     private string name;     private string sex;     private string age;      <span style="color:#ff6666;"><span style="color:#ff0000;">private WorkExperience work;</span> </span>//引用"工作经历"对象   public Resume(string name)   {      this.name = name;    <span style="color:#ffff00;">  </span><span style="color:#ff0000;"><span style="color:#ff0000;">work = new WorkExperience(); </span></span>   //在“简历”类实例化时同时实例化“工作经历”   }//设置个人信息:public void SetPersonalInfo(string sex,string age)   {      this.sex = sex;      this.age = age;   }//设置工作经历public void SetWorkExperience(<span style="color:#ff6666;">string workDate,string company</span>)  {      <span style="color:#ff6666;"> <span style="color:#ff0000;">work.WorkDate = workDate;       work.Company = company</span>;</span>  }//显示public void Display() {     Console.WriteLine("{0} {1} {2}",name, sex, age);     Console.WriteLine("工作经历:{0} {1}",<span style="color:#ff6666;"><span style="color:#ff0000;">work.WorkDate, work.Company</span></span>);  }  public Object Clone()   {       return (Object)this.MemberwiseClone();    }}</span>


客户端调用:

<span style="font-family:KaiTi_GB2312;font-size:24px;">static void Main(string[] args){   Resume a = new Resume("大鸟");   a.SetPersonalInfo("男","29");   a.SetWorkExperience("1998-2000","XX公司")   Resume b = (Resume)a.Clone();   b.setWorkExperience("1998-2006","YY企业")   Resume c = (Resume)a.Clone();   c.SetPersonalInfo("男","24");   c.SetWorkExperience("1998-2003","ZZ企业");   a.Display();        b.Display();   c.Display();    Console.Read();}</span>


结果显示:

大鸟 男 29
工作经历  1998-2003  ZZ公司

大鸟 男 29
工作经历  1998-2003  ZZ公司

大鸟 男 24
工作经历  1998-2003  ZZ公司


分析:

    因为“简历”对象里的数据都是string型的,而string是一种拥有值类型特点的特殊引用类型,(在这里例子中可以看成是值类型。)前者是值类型,后者是类类型(属于引用类型)。所以两次的结果是不一致的。

    当执行c.SetWorkExperience("1998-2003","ZZ企业")之后,内存区域的数据变成 1998-2003  ZZ公司。因为引用类型的a、b、c指向的是这一块内存区域。所以a、b、c三个的显示结果都为:工作经历  1998-2003  ZZ公司

 

               



1 0