在我写了一篇毫无价值的文章之后,经过进一步研究,补充了这部分,搞明白了为什么会出现上次的结果。最后面灰色字体是上一篇文章,有错误,仅供参考,大家只看黑色字体就可以了。
写完了上一篇文章,我不得不接受批评。很明显,我没有读过《 Applied Microsoft .NET Framework Programming 》一书,不然就不会进行这样的测试了。而且,测试方法也写得不对。经过事后研究,明白了其中的道理和本质。 反思如下:
经过反编译, .NET 中 “==” 是这样实现的:
public static bool operator == ( string a, string b)
{
return string . Equals ( a , b );
}
而 strings.Equals(string, string) 的实现如下:
public static bool Equals ( string a, string b)
{
if ( a == b )
{
return true ;
}
if (( a != null ) && ( b != null ))
{
return a . Equals ( b );
}
return false ;
}
最后 string.Equals(string) 的实现(通过内部调用实现的,具体怎么实现的就不得而知了):
[ MethodImpl ( MethodImplOptions . InternalCall )]
public extern bool Equals ( string value);
由此可见, == 先比较了两个对象的引用,如果引用相同直接返回 true 。如果引用不同就调用了 a.Equals(b) 。所以,在上面的程序中,所有 "67412" 都是同一个对象, == 也就比 Equals 快了一步,没有进入 string.Equals(string) 就返回 true 了。与 "67413" 比较的时候,引用不同了, == 通过调用 string.Equals(string) 才返回,所以又多用了一点比较引用的时间。如果两个字符串引用不同内容相同,那么用的时间跟上面返回 false 的那组测试应该是一样的。如果你以前只知道 == 是通过 Equals 实现的,现在你应该知道为什么第一组 == 比 Equals 快了。
下面是几条语句的反汇编的结果,也可以看出所有的 "67412" 都是来自同一个地址:
string toBeTested = "67412";
00000000 push ebp
00000001 mov ebp,esp
00000003 sub esp,8
00000006 push edi
00000007 push esi
00000008 push ebx
00000009 xor esi,esi
0000000b xor edi,edi
0000000d mov eax,dword ptr ds:[01AE1058h]
00000013 mov esi,eax
toBeTested.Equals("67412");
00000015 mov edx,dword ptr ds:[01AE1058h]
0000001b mov ecx,esi
0000001d cmp dword ptr [ecx],ecx
0000001f call dword ptr ds:[79C126F4h]
00000025 nop
result = toBeTested == "67412";
00000026 mov edx,dword ptr ds:[01AE1058h]
0000002c mov ecx,esi
0000002e call dword ptr ds:[79C126FCh]
00000034 movzx ebx,al
00000037 movzx eax,bl
0000003a mov edi,eax
result = toBeTested.Equals("67413");
0000003c mov edx,dword ptr ds:[01AE105Ch]
00000042 mov ecx,esi
00000044 cmp dword ptr [ecx],ecx
00000046 call dword ptr ds:[79C126F4h]
0000004c movzx ebx,al
0000004f movzx eax,bl
00000052 mov edi,eax
result = toBeTested == "67413";
00000054 mov edx,dword ptr ds:[01AE105Ch]
0000005a mov ecx,esi
0000005c call dword ptr ds:[79C126FCh]
00000062 movzx ebx,al
00000065 movzx eax,bl
00000068 mov edi,eax
}
0000006a nop
0000006b pop ebx
0000006c pop esi
0000006d pop edi
0000006e mov esp,ebp
00000070 pop ebp
00000071 ret
这回够彻底了吧。真相大白!还有一点没有说就是一位网友提到的 “ 字符串池 ” 的概念。我还不太了解,就不敢说了。
我看《 Applied Microsoft .NET Framework Programming 》去了 …… 同时我也向还没有读过此书又想了解 .NET 原理的同志们推荐它。
附:上一篇文章的内容
要比较两个字符串是否相等,有两种方法:
string toBeTested = "67412";
bool result;
result = toBeTested.Equals("67413");
和
result = toBeTested == "67413";
哪一种方法好呢?
测试程序:
int times = 100000000;
int start, end;
int i;
bool result;
string toBeTested = "67412";
start = System.Environment.TickCount;
for(i=0; i<times; i++)
{
result = toBeTested.Equals("67412");
}
end = System.Environment.TickCount;
Console.WriteLine("Equals True Time: " + (end-start)/1000.0 + " Seconds");
start = System.Environment.TickCount;
for(i=0; i<times; i++)
{
result = toBeTested == "67412";
}
end = System.Environment.TickCount;
Console.WriteLine("== True Time: " + (end-start)/1000.0 + " Seconds");
start = System.Environment.TickCount;
for(i=0; i<times; i++)
{
result = toBeTested.Equals("67413");
}
end = System.Environment.TickCount;
Console.WriteLine("Equals False Time: " + (end-start)/1000.0 + " Seconds");
start = System.Environment.TickCount;
for(i=0; i<times; i++)
{
result = toBeTested == "67413";
}
end = System.Environment.TickCount;
Console.WriteLine("== False Time: " + (end-start)/1000.0 + " Seconds");
结果:
Equals True Time: 3.234 Seconds
== True Time: 0.562 Seconds
Equals False Time: 3.391 Seconds
== False Time: 3.891 Seconds
可见当结果为 true 时, == 比 Equals() 快很多;当结果为 false 时, Equals() 略快于 == 。
结论:如果要比较的字符串相同的多,就用 == ;要比较的字符串中不同的多,就用 Equals() 。