对于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