你真的了解.NET中的String吗----详解String

  
概述
String 在任何语言中,都有它的特殊性,在 .NET 中也是如此。 它属于基本数据类型,也是基本数据类型中唯一的引用类型。字符串可以声明为常量,但是它却放在了堆中。希望通过本文能够使大家对 .NET 中的 String 有一个深入的了解。
不可改变对象
.NET String 是不可改变对象,一旦创建了一个 String 对象并为它赋值,它就不可能再改变,也就是你不可能改变一个字符串的值。这句话初听起来似乎有些不可思议,大家也许马上会想到字符串的连接操作,我们不也可以改变字符串吗?看下面这段代码: 
运行 果:
1234
5678
 
字符串的比较
.NET 中,对字符串的比较操作并不仅仅是简单的比较二者的值, = = 操作首先比较两个字符串的引用,如果引用相同,就直接返回 True ;如果不同再去比较它们的值。所以如果两个值相同的字符串的比较相对于引用相同的字符串的比较要慢,中间多了一步判断引用是否相同。看下面这段代码:
  1   using  System;
 
2  
 
3   namespace  Demo3
 
4    {
 
5      /// <summary>
 6     /// String类型的比较
 7     /// </summary>
 8     public class Test
 
9      {
10         public static void Main(string[] args)
11          {
12             string a = "1234";
13             string b = "1234";
14             string c = "123";
15             c += "4";
16 
17             int times = 1000000000;
18             int start,end;
19             
20              ///测试引用相同所用的实际时间
21             start = Environment.TickCount;
22             for(int i=0;i<times;i++)
23              {
24                 if(a==b)
25                  {}
26             }

27             end = Environment.TickCount;
28             Console.WriteLine((end-start));
29             
30              ///测试引用不同而值相同所用的实际时间
31             start = Environment.TickCount;
32             for(int i=0;i<times;i++)
33              {
34                 if(a==c)
35                  {}
36             }

37             end = Environment.TickCount;
38             Console.WriteLine((end-start));
39 
40             Console.ReadLine();
41         }

42     }

43 }

 
行的 果(运行的 果可能有些不同):
1671
4172
 
由此我们看出值相同时的比较用 = = 比引用相同时的比较慢了好多。这里仅仅是一个测试,因为做这样的比较并没有任何实际的意义。
有一点需要明确的是, .NET == Equals() 内部机制完全是一样的, == 是它的一个重载。
1   public   static   bool   operator   == ( string  a,  string  b)
2    {
3       return string.Equals(a, b);
4 }

5  
1   public   static   bool  Equals( string  a,  string  b)
 
2    {
 
3       if (a == b)
 
4        {
 
5             return true;
 
6       }

 
7       if ((a != null&& (b != null))
 
8        {
 
9             return a.Equals(b);
10       }

11       return false;
12 }

 
字符串驻留
看一下这段代码:
1   using  System;
 
2  
 
3   namespace  Demo4
 
4    {
 
5      ///<summary>
 6     /// String的驻留
 7     /// </summary>
 8     public class Test
 
9      {
10         public static void Main(string[] args)
11          {
12             string a = "1234";
13             string s = "123";
14             s += "4";
15 
16             string b = s;
17             string c = String.Intern(s);
18 
19             Console.WriteLine((object)a == (object)b);
20             Console.WriteLine((object)a == (object)c);
21             Console.ReadLine();
22         }

23     }

24 }


 
执行的结果:
false
true
 
段代 中,比 较这 两个 发现 它的引用并不是一 的。如果要想是它 的引用相同,可以用Intern() 函数来进行字符串的驻留(如果有这样的值存在)。
StringBuilder 对象
通过上面的分析可以看出, String 类型在做字符串的连接操作时,效率是相当低的,并且由于每做一个连接操作,都会在内存中创建一个新的对象,占用了大量的内存空间。这样就引出 StringBuilder 对象, StringBuilder 对象在做字符串连接操作时是在原来的字符串上进行修改,改善了性能。这一点我们平时使用中也许都知道,连接操作频繁的时候,使用 StringBuilder 对象。 但是这两者之间的差别到底有多大呢?来做一个测试:
1   using  System;
 
2   using  System.Text;
 
3  
 
4   namespace  Demo5
 
5    {
 
6      ///<summary>
 7     /// String和StringBulider比较
 8     /// </summary>
 9     public class Test
10      {
11         public static void Main(string[] args)
12          {
13             string a = "";
14             StringBuilder s = new StringBuilder();
15 
16             int times = 10000;
17             int start,end;
18             
19              ///测试String所用的时间
20             start = Environment.TickCount;
21             for(int i=0;i<times;i++)
22              {
23                 a += i.ToString();
24             }

25             end = Environment.TickCount;
26             Console.WriteLine((end-start));
27             
28              ///测试StringBuilder所用的时间
29             start = Environment.TickCount;
30             for(int i=0;i<times;i++)
31              {
32                 s.Append(i.ToString());
33             }

34             end = Environment.TickCount;
35             Console.WriteLine((end-start));
36 
37             Console.ReadLine();
38         }

39     }

40 }

 
运行 果:
884
0
 
通过上面的分析,可以看出用 String 来做字符串的连接时效率非常低,但并不是所任何情况下都要用 StringBuilder ,当我们连接很少的字符串时可以用 String ,但当做大量的或频繁的字符串连接操作时,就一定要用 StringBuilder
1   using  System;
 
2  
 
3   namespace  Demo1
 
4    {
 
5      ///<summary>
 6     /// String连接测试
 7     /// </summary>
 8     public class Test
 
9      {
10         public static void Main(string[] args)
11          {
12             string a = "1234";
13             Console.WriteLine(a);
14 
15             a += "5678";
16             Console.WriteLine(a);
17             Console.ReadLine();
18         }

19     }

20 }

运行的结果:

1234

12345678

看起来我似乎已MyStr的值从“1234”改为了“12345678”。事实是这样的吗?实际上并没有改变。在第5行代码中创建了一个String对象它的值是“1234”,MyStr指向了它在内存中的地址;第七行代码中创建了一个新的String对象它的值是“12345678”,MyStr指向了新的内存地址。这时在堆中其实存在着两个字符串对象,尽管我们只引用了它们中的一个,但是字符串“1234”仍然在内存中驻留。

引用类型

前面说过String是引用类型,这就是如果我们创建很多个相同值的字符串对象,它在内存中的指向地址应该是一样的。也就是说,当我们创建了字符串对象a,它的值是“1234”,当我们再创建一个值为“1234”的字符串对象b时它不会再去分配一块内存空间,而是直接指向了a在内存中的地址。这样可以确保内存的有效利用。看下面的代码:

1 using System;
 2
 3 namespace Demo2
 4 {
 5     /**////<summary>
 6     /// String
引用测试
 7     /// </summary>
 8     public class Test
 9      {
10         public static void Main(string[] args)
11          {
12             string a = "1234";
13
14             Console.WriteLine(a);
15
16             Test.Change(a);
17
18             Console.WriteLine(a);
19             Console.ReadLine();
20         }
21
22         public static void Change(string s)
23          {
24             s = "5678";
25         }
26     }
27 }

运行果:

1234

1234

  做一个小改,注意Change(ref string s)

  1   using  System;
 
2  
 
3   namespace  Demo2
 
4    {
 
5      /// <summary>
 6     /// String引用类型测试
 7     /// </summary>
 8     public class Test
 
9      {
10         public static void Main(string[] args)
11          {
12             string a = "1234";
13 
14             Console.WriteLine(a);
15 
16             Test.Change(ref a);
17 
18             Console.WriteLine(a);
19             Console.ReadLine();
20         }

21 
22         public static void Change(ref string s)
23          {
24             s = "5678";
25         }

26     }

27 }

28  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值