在我写了一篇毫无价值的文章之后,经过进一步研究,补充了这部分,搞明白了为什么会出现上次的结果。最后面灰色字体是上一篇文章,有错误,仅供参考,大家只看黑色字体就可以了。
写完了上一篇文章,我不得不接受批评。很明显,我没有读过《Applied Microsoft .NET Framework Programming》一书,不然就不会进行这样的测试了。而且,测试方法也写得不对。经过事后研究,明白了其中的道理和本质。反思如下:
经过反编译,.NET中“==”是这样实现的:<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
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()。