6. 区别值类型和引用类型

 

一、总的区别

    首先说说什么类型是值类型,例如:int、float、bool之类的基础类型,以及用struct定义的类型,如:DateTime。除此外,如string,数组,以及用class定义的类型等都是引用类型。对于C#来说,很难罗列出所有类型进行一一分别,这需要自己在编码过程中进行分析总结。

值类型引用类型
内存分配地点分配在栈中分配在堆中
效率效率高,不需要地址转换效率低,需要进行地址转换
内存回收使用完后,立即回收使用完后,不是立即回收,等待GC回收
赋值操作进行复制,创建一个同值新对象只是对原有对象的引用
函数参数与返回值是对象的复制是原有对象的引用,并不产生新的对象
类型扩展不易扩展容易扩展,方便与类型扩展


二、赋值区别

static void Main(string arg[])  
{  
    int x = 10;  
    int y = x;  
    Console.WriteLine(x.ToString() + "," + y.ToString());//输出的结果是:10,10  
    y = 20;  
    Console.WriteLine(x.ToString() + "," + y.ToString());//输出的结果是:10,20  
    int[] arry = new int[1];  
    int[] arry1 = arry;  
    arry[0] = 10;  
    Console.WriteLine(arry[0].ToString() + "," + arry1[0].ToString());//输出的结果是:10,10  
    arry1[0] = 20;  
    Console.WriteLine(arry[0].ToString() + "," + arry1[0].ToString());//输出的结果是:20,20  
    string str1 = "liao";  
    string str2 = str1;  
    Console.WriteLine(str1 + "," + str2);//输出的结果是:liao,liao  
    str1 = "xiao";  
    Console.WriteLine(str1 + "," + str2);//输出的结果是:xiao,liao  
}   

 

1、因int 是值类型,int x  int y 内存中就有两个地方存储x,y;所以当改变x或y的值时,都不会改变另一个变量的值。
2、因int [] arry,int []arry1 是数组,数组是引用类型,所以这两个变量引用了同一个对象(数组)
所以当 改变某一个引用指向的对象的属性同时也会影响到所有其他指向这个对象的引用,所以当arry1[0]的值改成20时,arry[0]的值也随着改变成20;最后的arry[0]和arry1[0]的值都为20;不过虽然字符类型string也是引用类型,但它的工作方式更像值类型,既当str1的值改成"xiao"时,新创建了一个string对象,str1引用这个新的string对象;str2仍然引用原来string对象。产生这种行为的原因是string对象是恒定的,也就是说,一旦一个string对象被创建,它的值就不能再修改,所以当改变一个字符串变量的值的时候,仅仅是新创建了一个包含修改内容的新的string对象。
三、作为函数参数或者返回值
class Program  
{  
    public static void add(int k)  
    {  
        k = k + 39;  
    }  
  
    public static void add(ref int i)  
    {  
        i = i + 39;  
  
    }  
  
    public static void add(int[] j)  
    {  
        j[0] = j[0] + 39;  
    }  
  
    public static void astr(ref string sy)  
    {  
        sy = "ddd";  
    }  
  
    static void Main(string[] args)  
    {  
        int[] ary = new int[1];  
        int[] ary1 = ary;  
        ary[0] = 1;  
        add(ary[0]);  
        Console.WriteLine(ary[0].ToString()); //输出的结果是:1  
        add(ref ary[0]);  
        Console.WriteLine(ary[0].ToString()); //输出的结果是:40  
        add(ary);  
        Console.WriteLine(ary[0].ToString()); //输出的结果是:79  
        string str4 = "liaoxiaol";  
        astr(ref str4);                 //输出的结果是:ddd //str4的值已改变  
        Console.WriteLine(str4);  
    }  
}  

  说明:
1、对于值类型的变量:要想在函数中对传进去的参数做真正的修改,需要借助于ref这个关键字,所以当执行add(ary[0])后,arry[0]的值时并没有改变;而当执行add(ref ary[0])后,ary[0]的值,就变成了1+39=40;
2、对于引用类型的变量,则和值变量相反;而在实际应用中我们并不想引用类型变量作为函数参数传入后,其值有所心改变,要做到这一点需要为“引用类型”提供一个额外的clone函数,所以当执行add(arry)后,arry[0]的值就变成了40+39=79;
3、虽然string类型也是引用类型但前面也说过string 类型的工作更像值类型。

附加:
对于引用类型来说,提供一个clone函数不是一件容易的事情,尤其出现引用类型嵌套的时候,在C#中,尤其自己定义类型的时候,常常由于是用struct来定义还是用class来定义,即是定义一个值类型还是一个引用类型呢。在这本书上给了几个判定条件,如果如下几点都满足的话,建议用struct来定义为值类型,否则用class定义为引用类型。

1、这个类型是否主要为了数据存储;
2、是否只通过属性来访问对象的数据成员;
3、这个类型是否不会有子类型;
4、在程序处理的时候不会把这个类型对象通过多态来处理。
总而言之,在C#中,就是把底层面的数据用值类型来处理,而包含复杂操作,需要进行扩展的数据用引用类型来处理。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值