C#基础知识点总结
2010-12-25 09:26
344 查看
最近重新复习了一个c#基础知识,在测试StringBuilder与字符串连接的比较时,没想到二者的差距竟然如此之大,用StringBuilder连接字符50000次竟然是0毫秒,而用字符串连接为1750毫秒。当连接500000次的结果差距更不用说了,下面总结一下学习c#的一些知识点:
1.StringBuilder与字符串连接比较
1 Console.WriteLine("String routine");
2 string a = "a";
3 string str = string.Empty;
4 int istart, istop;
5 istart = Environment.TickCount & Int32.MaxValue;
6 Console.WriteLine("Start: " + istart);
7 for (int i = 0; i < 50000; i++)
8 {
9 str += a;
}
istop = Environment.TickCount;
Console.WriteLine("Stop: " + Environment.TickCount);
Console.WriteLine("Difference: " + (istop - istart));
Console.WriteLine("StringBuilder routine");
StringBuilder builder = new StringBuilder();
istart = Environment.TickCount & Int32.MaxValue;
Console.WriteLine("Start: " + istart);
for (int i = 0; i < 50000; i++)
{
builder.Append(a);
}
istop = Environment.TickCount;
str = builder.ToString();
Console.WriteLine("Stop: " + Environment.TickCount);
Console.WriteLine("Difference: " + (istop - istart));
Console.Read();
执行结果却大吃一惊,知道用字符串拼接速度慢,但没想到会慢到如此地步,下图是拼接50000个字符:
当拼接500000个字符时,执行结果为:
出现这个结果的原因是:第一是字符串是不可变的,每次字符串变量的内容发生改变时,都必须重新分配内存。例如上面迭代50000次的循环,每次迭代都将一个字符连接到字符串,这样,内存中最终将有50000个字符串,每个字符串与其前面的字符串想比只差1个字符,第二是StringBuilder类是通过分配一个工作区解决这个问题,并在这个工作区中可以对字符串进行追加、插入、删除、移除和替换等操作。也就是说所有的操作都在一个缓存中进行,不需要任何内存分配,所以速度还是明显不一样。。。
2. 深拷贝和浅拷贝
1 test mytest = new test("Joanna");
2 mytest.Age = 36;
3 test clone1 = (test)mytest.Clone(); //浅拷贝
4 test clone2 = mytest; //深拷贝
5 Console.WriteLine(Object.ReferenceEquals(mytest.Name, clone1.Name)); //true
6 Console.WriteLine(Object.ReferenceEquals(mytest.Name, clone2.Name)); //true
7 Console.WriteLine(Object.ReferenceEquals(mytest.Age, clone1.Age)); //false
8 mytest.Name = "Julie";
9 Console.WriteLine(Object.ReferenceEquals(mytest.Name, clone1.Name)); //false
Console.WriteLine(Object.ReferenceEquals(mytest.Name, clone2.Name)); //true
Console.WriteLine(Object.ReferenceEquals(mytest.Age, clone2.Age)); //false
Console.Read();
类代码如下:
13 public class test : ICloneable
14 {
15 public int Age;
16 public String Name;
17 public test(string myname)
18 {
19 Name = myname;
20 }
21 public object Clone()
22 {
23 return MemberwiseClone();
24 }
25 }
从上面代码中我们可以看出如下几点:
(1)当字段为引用类型时,不是深拷贝还是浅拷贝,指针都指向同一个地址,如上面代码中的5和6的比较。
(2)当字段为值类型时,不管是浅拷贝还是深拷贝,指针指向都为不同的地址,如上面代码中的9和11的比较。 (3)当字符串不同时,浅拷贝指向的指针和原来的指针不同,如“9”,深拷贝指向的还是为同一个地址如“11”
出现这种情况的原因如下:
(1) 浅拷贝创建原对象类型的一个新实例,然后将原对象的非静态字段复制到新对象。对于引用类型字段,则只复制指向该值的指针。因些,拷贝的对象和原对象指向相同的引用对象。
(2)深拷贝是复制所有字段,它会创建引用对象的副本,并在副本中提供这些对象的引用。
(3)CLR还在内存中预留了拘留池,是为了避免存储重复的字符串值。在为字符串变量赋值时,先检查字符串值在拘留池中是否存在指向该字符串的指针,如果存在,则把指针指向已有的对象,如果不存在,则另开辟一块内存,用来存储字符串,将指针指向该内存地址,并将拘留池中的指针也指向该内存地址。这也是为什么字符串不同时,浅拷贝与深拷贝的指向的地址也会不同。
3.值类型和引用类型:
(1)内存分配:引用类型分配到堆中,而值类型分配到线程栈或调用栈中。创建引用类型时,会初始化为null,表示它不指向任何数据,值类型则初始化为0.
(2)内存释放:变量超出其作用域时,会释放栈中的内存,而堆内存达到系统内存的下限阈值时,会启动垃圾回收机制,释放堆中内存。
(3)变量赋值:变量设置为引用类型时,它会接收指向原对象的一个指针,而不是对象值本身,变量设置为值类型时,会逐字段地复制原变量,并赋给新变量。
1.StringBuilder与字符串连接比较
1 Console.WriteLine("String routine");
2 string a = "a";
3 string str = string.Empty;
4 int istart, istop;
5 istart = Environment.TickCount & Int32.MaxValue;
6 Console.WriteLine("Start: " + istart);
7 for (int i = 0; i < 50000; i++)
8 {
9 str += a;
}
istop = Environment.TickCount;
Console.WriteLine("Stop: " + Environment.TickCount);
Console.WriteLine("Difference: " + (istop - istart));
Console.WriteLine("StringBuilder routine");
StringBuilder builder = new StringBuilder();
istart = Environment.TickCount & Int32.MaxValue;
Console.WriteLine("Start: " + istart);
for (int i = 0; i < 50000; i++)
{
builder.Append(a);
}
istop = Environment.TickCount;
str = builder.ToString();
Console.WriteLine("Stop: " + Environment.TickCount);
Console.WriteLine("Difference: " + (istop - istart));
Console.Read();
执行结果却大吃一惊,知道用字符串拼接速度慢,但没想到会慢到如此地步,下图是拼接50000个字符:
当拼接500000个字符时,执行结果为:
出现这个结果的原因是:第一是字符串是不可变的,每次字符串变量的内容发生改变时,都必须重新分配内存。例如上面迭代50000次的循环,每次迭代都将一个字符连接到字符串,这样,内存中最终将有50000个字符串,每个字符串与其前面的字符串想比只差1个字符,第二是StringBuilder类是通过分配一个工作区解决这个问题,并在这个工作区中可以对字符串进行追加、插入、删除、移除和替换等操作。也就是说所有的操作都在一个缓存中进行,不需要任何内存分配,所以速度还是明显不一样。。。
2. 深拷贝和浅拷贝
1 test mytest = new test("Joanna");
2 mytest.Age = 36;
3 test clone1 = (test)mytest.Clone(); //浅拷贝
4 test clone2 = mytest; //深拷贝
5 Console.WriteLine(Object.ReferenceEquals(mytest.Name, clone1.Name)); //true
6 Console.WriteLine(Object.ReferenceEquals(mytest.Name, clone2.Name)); //true
7 Console.WriteLine(Object.ReferenceEquals(mytest.Age, clone1.Age)); //false
8 mytest.Name = "Julie";
9 Console.WriteLine(Object.ReferenceEquals(mytest.Name, clone1.Name)); //false
Console.WriteLine(Object.ReferenceEquals(mytest.Name, clone2.Name)); //true
Console.WriteLine(Object.ReferenceEquals(mytest.Age, clone2.Age)); //false
Console.Read();
类代码如下:
13 public class test : ICloneable
14 {
15 public int Age;
16 public String Name;
17 public test(string myname)
18 {
19 Name = myname;
20 }
21 public object Clone()
22 {
23 return MemberwiseClone();
24 }
25 }
从上面代码中我们可以看出如下几点:
(1)当字段为引用类型时,不是深拷贝还是浅拷贝,指针都指向同一个地址,如上面代码中的5和6的比较。
(2)当字段为值类型时,不管是浅拷贝还是深拷贝,指针指向都为不同的地址,如上面代码中的9和11的比较。 (3)当字符串不同时,浅拷贝指向的指针和原来的指针不同,如“9”,深拷贝指向的还是为同一个地址如“11”
出现这种情况的原因如下:
(1) 浅拷贝创建原对象类型的一个新实例,然后将原对象的非静态字段复制到新对象。对于引用类型字段,则只复制指向该值的指针。因些,拷贝的对象和原对象指向相同的引用对象。
(2)深拷贝是复制所有字段,它会创建引用对象的副本,并在副本中提供这些对象的引用。
(3)CLR还在内存中预留了拘留池,是为了避免存储重复的字符串值。在为字符串变量赋值时,先检查字符串值在拘留池中是否存在指向该字符串的指针,如果存在,则把指针指向已有的对象,如果不存在,则另开辟一块内存,用来存储字符串,将指针指向该内存地址,并将拘留池中的指针也指向该内存地址。这也是为什么字符串不同时,浅拷贝与深拷贝的指向的地址也会不同。
3.值类型和引用类型:
(1)内存分配:引用类型分配到堆中,而值类型分配到线程栈或调用栈中。创建引用类型时,会初始化为null,表示它不指向任何数据,值类型则初始化为0.
(2)内存释放:变量超出其作用域时,会释放栈中的内存,而堆内存达到系统内存的下限阈值时,会启动垃圾回收机制,释放堆中内存。
(3)变量赋值:变量设置为引用类型时,它会接收指向原对象的一个指针,而不是对象值本身,变量设置为值类型时,会逐字段地复制原变量,并赋给新变量。
相关文章推荐
- C#中的数组基础知识点总结
- C#基础知识点总结
- C#泛型基础知识点总结
- 【黑马程序员】C#基础中一些知识点总结备忘
- C#基础总结之七面向对象知识点总结1
- C#基础总结之八面向对象知识点总结-继承与多态-接口
- C#反射之基础应用实例总结
- 软件测试管理基础重点知识点总结
- C#知识点总结系列:3、C#中Delegate和Event以及它们的区别
- C#常用知识点总结
- C#基础知识之方法重载总结
- 知识点总结: Java 面试宝典 2013版(超长版) - Java 基础部分
- C++基础知识点总结四
- canvas基础知识点总结
- 黑马程序员-----踏踏实实基础C#基础总结
- [c#基础教程]C#泛型列表List<T>基本用法总结
- 牛客网 7-28 网络基础 操作系统 编译与体系结构 30题知识点总结
- 基础知识(C#语法、数据库SQL Server)回顾与总结
- C#基础总结
- 基础总结知识点-第三章:HTML语言