C#中值类型和引用类型的分析

来源:互联网 发布:欧洲网络与信息安全局 编辑:程序博客网 时间:2024/05/20 05:28

     对于C#的值类型和引用类型的本质区别和他们的用法还是比较的模糊,今天在这里在总结一下自己温故而知新的知识:

     在C#中有两种类型的数据,一种是值类型,另一种是引用类型。

值类型包括:内置值类型、用户自定义值类型、和枚举,如 int,float bool 等,以及struct等。

引用类型包括接口类型、用户自定义的类、委托等。如 string 、DateTime、数组等。

值类型是存储在堆栈中,而引用类型是存储在托管堆上,C#程序首先被编译成IL程序,然后在托管执行。值类型直接从堆栈中里面取值,而引用类型必须要先从堆栈里面取出它的地址,再根据这个地址在堆里找到对应的值。


值类型与饮用类型的本质区别有以下几点:

1.内存分配:   值类型是分配在栈中的;而引用类型是分配在堆中。

2.效率:         值类型效率高,不需要地址转换;引用类型效率较低,需要进行地址转换。

3.内存回收:  值类型使用完后立即回收;引用类型使用完后不立即回收,而是交给GC处理回收。

4.赋值操作:   值类型是创建一个新对象;引用类型创建一个引用。

5.类型扩展:  值类型不易扩展,所有值类型都是密封(seal)的,所以无法派生出新的值类型;引用类型具有多态的特性方便扩展。

这是别人的总结,我在这里拿来用下。

下面我在说说它们在用法上的区别了,C#之所以要分这两种数据类型的原因是达到更好的性能,把一些基本类型如int、bool规定为值类型,而把包含许多字段的较大类型规定为引用类型,如用户自定义的类。值类型主要是负责存储数据,引用类更多是用在代码的重用性上。

下面有几个典型的例子分析一下:

1.string 类型和StringBuilder

先说一下单独说下string,在我刚开始学习C#的时候知道string是引用类型的数据,也经常的把string类型的数据作为方法的参数然而我发现了一个小问题,那就是在我把这个引用类型作为参数传递给方法做处理的时候,传进来的string变量已经改变,但是原来的string变量的值还是原来的值,那不就是说和引用类型的本质有冲突,在操作引用类型的时候实际是根据地址操作堆中的数据,方法里面改变了引用类型的值,那么原来的那个变量的值也随之而改变。我迷惑了很久,终于才知道其实string类型有点特殊,在string变量赋值的时候其实是新创建了一个对象,所指向的堆就改变了。正是因为这样在频繁操作一个字符串的时候string要不断的创建新对象,然后舍弃就得对象。它的性能有些差了,然后系统还提供了一个StringBuilder对象,在它的内部实际上有一个足够长的字符数组用于存放字符串对象,当字符串长度没有超过字符数据长度时,所有操作都是针对同一个字符数组的。当长度超过时,StringBuilder将创建一个更长的数组,把原来的数据复制到新的数据中。

看完这两个例子就知道他们的区别:

1.性能的比较:

+ expand sourceview plaincopy to clipboardprint?
static void Main(string[] args)  
      {  
          StringTest();  
          StringBuilderTest();  
      }  
 
      private static void StringTest()  
      {  
          string str = "";  
          DateTime startTime = DateTime.Now;//记录起始时间  
          for (int i = 0; i < 100000; i++)  
          {  
              str += "a";  
          }  
          DateTime endTime = DateTime.Now;//记录计算结束时间  
 
          TimeSpan timeSpan = endTime - startTime; //得到时间差  
 
          Console.WriteLine("stirng操作10000此需要的时间:"+timeSpan.ToString());  
 
      }  
 
      private static void StringBuilderTest()  
      {  
          StringBuilder str =new StringBuilder ("");  
          DateTime startTime = DateTime.Now;//记录起始时间  
          for (int i = 0; i < 1000000; i++)  
          {  
              str.Append("a");  
          }  
          DateTime endTime = DateTime.Now;//记录计算结束时间  
 
          TimeSpan timeSpan = endTime - startTime; //得到时间差  
 
          Console.WriteLine("stirngBuilder操作100000此需要的时间:" + timeSpan.ToString());  
      } 
  static void Main(string[] args)
        {
            StringTest();
            StringBuilderTest();
        }

        private static void StringTest()
        {
            string str = "";
            DateTime startTime = DateTime.Now;//记录起始时间
            for (int i = 0; i < 100000; i++)
            {
                str += "a";
            }
            DateTime endTime = DateTime.Now;//记录计算结束时间

            TimeSpan timeSpan = endTime - startTime; //得到时间差

            Console.WriteLine("stirng操作10000此需要的时间:"+timeSpan.ToString());

        }

        private static void StringBuilderTest()
        {
            StringBuilder str =new StringBuilder ("");
            DateTime startTime = DateTime.Now;//记录起始时间
            for (int i = 0; i < 1000000; i++)
            {
                str.Append("a");
            }
            DateTime endTime = DateTime.Now;//记录计算结束时间

            TimeSpan timeSpan = endTime - startTime; //得到时间差

            Console.WriteLine("stirngBuilder操作100000此需要的时间:" + timeSpan.ToString());
        }

 string操作10000次需要13秒钟,而StringBuilder操作100000只需要0.3秒,效率是string的几百倍,很明显StirngBuilder大胜!

 ,


2.引用的区别:

+ expand sourceview plaincopy to clipboardprint?
static void Main(string[] args)  
       {  
           StringBuilder str = new StringBuilder ("aa");  
           UserStringBuilder(str);  
           Console.WriteLine(str);    // aaModifyByUserStringStringBuilder  
 
           string str1 = "aa";  
           UserString(str1);  
           Console.WriteLine(str1);   //aa  
       }  
 
       private static void UserString(string str)  
       {  
           str = "MofifyByUserString";  
       }  
 
       private static void UserStringBuilder(StringBuilder str)  
       {  
           str.Append("ModifyByUserStringStringBuilder");  
             
       } 
 static void Main(string[] args)
        {
            StringBuilder str = new StringBuilder ("aa");
            UserStringBuilder(str);
            Console.WriteLine(str);    // aaModifyByUserStringStringBuilder

            string str1 = "aa";
            UserString(str1);
            Console.WriteLine(str1);   //aa
        }

        private static void UserString(string str)
        {
            str = "MofifyByUserString";
        }

        private static void UserStringBuilder(StringBuilder str)
        {
            str.Append("ModifyByUserStringStringBuilder");
           
        }


这个例子很明显string操作的时候是在内存中创建了一新的的对象,而StringBuilder则只针对一个对象的操作,所以StringBuilder的性能上要高于string. 在频繁处理字符串的时候最好用StringBuilder。


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/xiongzhiqiang123/archive/2009/08/06/4418403.aspx

原创粉丝点击