浅谈值类型和引用类型的区别

  值类型和引用类型几乎囊括了c#中所有类型,重要性贯穿整个程序生涯,开发时间长短对于这两种类型理解深刻程度不同,但是开发中总要考虑到这两种类型的区别来使用。

  那么什么是值类型?什么是引用类型呢?

       ——值类型(value type)

           ~值类型是一种将地址和值都存储在栈内,由系统自动释放的而指的实际值得一种数据类型。值类型的代表的是具体的值,在声明类型时候自动由线程开启一个内存,只占据极少内存。

           ~常见的值类型:整型:Int,长整型:long,布尔类型型:bool,浮点型:float,枚举:enum,结构体:struct。

           ~而所有所有的值类型都继承自System.ValueType,System.ValueType是继承于System.Object。所以可以说值类型间接继承于System.Object。

           ~修改值类型的属性会直接修改值,而且需要整体赋值,无法通过引用赋值。

        ——引用类型(reference type)

          ~引用类型是一种将类型的值引用表示的数据类型。如果为某个变量赋于一个引用,则该变量将引用地址的指向值。
         ~ 引用类型代表的是实际值的引用,而非实际值,可以理解为一个类型声明一个不同的名称,名称虽不同,但是指向是一样的。
          ~引用类型包括字符串:string,数组[],接口:interface,委托:delegate,用户自定义类:class等。
          ~所有的引用类型都直接继承自System.Object。
 
        那么根据属性的不同,两种类型就有着很大的不同。那么通过测试谈谈两种类型的不同在哪里。
 
       ——引用类型和值类型的区别
 
        1、在使用时候,由于值类型直接使用的值,而引用类型是通过先查找到地址再寻找值,那么值类型的存取速度就引用类型存取速度快
        2、值类型的无论值和地址全部在栈中,而引用类型的地址都在内存堆中,值保存在栈中。
 
        根据下图流程,可以看出引用类型分两步拿到值,所以引用类型存取速度慢。
        
 
        3、在传递参数时候,值类型传递的是具体的值,而引用类型传递的是地址。
         
1     int i = 0;
2     int testValue(int temp)
3     {
4         temp = 4; return temp;
5     }
6     testValue(i);
7     Debug.Log(i);
       在我们调用这个方法,虽然i作为参数传递,但是 i 的值是不会变化的。这里实际上是出现了两个变量,一个 i ,一个temp。修改的只是temp的值,而非 i 的值。
       但是假如修改一下,将i的引用传递进去,那么i的值就会变化了。比如:
1     int i = 0;
2     void testValue( ref int temp)
3     {
4         temp = 4;
5     }
6     testValue(ref i);
7     Debug.Log(i);

             那么这个时候,i的值就变成了4。因为ref是将 i 的地址传递,此时变量temp和 i 引用的是同一个地址,那么修改地址的值,i 的值就会变化。

             ps:ref和out是在传递参数时候传递值类型的地址,不同的是ref需要赋初始值,所以可以理解为ref是可进可出,out只出不进。

            4、在赋值时候,值类型初始化后才能赋值。主要体现在结构体和类。

                 在这里简单列举下结构体和类的区别:

                        (1)构造函数:结构体构造必须带参,引用类型可带参,可不带参。

                        (2)定义字段:结构体只有加上static或者const才能赋初始值,引用类型可赋可不赋。

                        (3)默认:结构体默认是公有的,而类默认是私有的。

                        (4)可继承性:结构体不能被继承。

                 首先举例子说明值类型需要初始化赋值:

 1 public class A
 2 {
 3    public  int i = 0;
 4     public  double d = 0;
 5 }
 6 public struct B
 7 {
 8     public  int i;
 9     public  double d;
10 }
11 public class test {
12    
13     B GetB()
14     {
15         B b = new B();
16         return b;
17     }
18     A GetA()
19     {
20         A a = new A();
21         return a;
22     }
23      void Main()
24     {
25         GetB().i = 1;//这一行就会报错
26         GetA().i = 1;
27     }
28 }

       报错信息:GetB返回值不是变量,是因为返回结构体是一个值,不同于引用类型返回了一个地址,直接通过地址查找子对象毫无问题。返回的结构体要想修改值,还需要一个变量去指向它。所以结构体里的子对象只能通过变量来修改,因为变量是一个具体的值。

       ——特殊的引用类型:string

       string是引用类型,可它身上几乎没有引用类型的共性,而全身上下都属于值类型的范畴,因为可以理解为string是一个值类型。这是为什么呢?
       1、string虽然是引用类型,但是在修改它的值的时候,会重新开辟一次内存堆,创建新的对象,原因就在于字符串的恒定,不可变,所以无法说两个string地址指向了一处。但是字符串的驻留技术使得它变成引用类型。这个可以自行搜索某些文章。
             下面说明一下创建新的对象:
                    由于字符串是不可变的,而c#封装的有改变字符串的方法,举个例子:SubString。
                     string a = " "; a.Substring(1,2); 
                   这个过程a先声明一个变量,a.SubString开始从1截取到2结束又生成一个变量在内存堆中。那么这个过程其实在内存堆中有了两个变量,a仍然是初始值,但是用一个变量去接内存堆中的变量,就是另一个变量
       2、string不可变性意味着传递参数虽然是引用地址,但是修改不了它的值,类似于值类型。
 
            关于值类型和引用类型的区别,就说到这里吧。欢迎指正错误,另外本人QQ群:478462732希望大家赏脸。
 
 

猜你喜欢

转载自www.cnblogs.com/Quele/p/9187445.html