Java在字符串的处理方面和C#基本一致,但是仍旧存在细微差别。
在C#中,比较两个字符串可以使用==号,因为在C#中,比较两个字符串的时候,编译器会重载字符串比较方法,比如下面的代码:
在C#中,比较两个字符串可以使用==号,因为在C#中,比较两个字符串的时候,编译器会重载字符串比较方法,比如下面的代码:
public static void Test()
{
string str1 = "strings";
string str2 = "strings";
bool isEqual = str1 == str2;
Console.WriteLine(isEqual);
}
输出的结果为:True
当我们查看IL代码的时候,内部的操作就比较清楚了:
.method public hidebysig static void Test() cil managed
{
// 代码大小 27 (0x1b)
.maxstack 2
.locals init ([0] string str1,
[1] string str2,
[2] bool isEqual)
IL_0000: ldstr "strings"
IL_0005: stloc.0
IL_0006: ldstr "strings"
IL_000b: stloc.1
IL_000c: ldloc.0
IL_000d: ldloc.1
IL_000e: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_0013: stloc.2
IL_0014: ldloc.2
IL_0015: call void [mscorlib]System.Console::WriteLine(bool)
IL_001a: ret
} // end of method Class1::Test
上面的 IL_000e 行反映了编译器在比较两个字符串时的操作,即调用了System.String类中的一个方法op_Equality(string, string)对两个字符串进行比较。
当我们深入op_Equality(string, string)方法体内的时候,我们就很清楚的知道C#比较两个字符串多的算法:
00000000 push edi
00000001 push esi
00000002 push ebx
00000003 mov edi,ecx
00000005 mov esi,edx
00000007 cmp edi,esi
00000009 jne 00000014
0000000b mov eax,1
00000010 pop ebx
00000011 pop esi
00000012 pop edi
00000013 ret
00000014 test edi,edi
00000016 je 0000001C
00000018 test esi,esi
0000001a jne 00000022
0000001c xor eax,eax
0000001e pop ebx
0000001f pop esi
00000020 pop edi
00000021 ret
00000022 mov edx,esi
00000024 mov ecx,edi
00000026 cmp dword ptr [ecx],ecx
00000028 call dword ptr ds:[79C126F4h]
0000002e movzx ebx,al
00000031 mov eax,ebx
00000033 pop ebx
00000034 pop esi
00000035 pop edi
00000036 ret
由上面的汇编代码可以看出,C#首先会比较两个字符串的地址是否相等:
00000007 cmp edi,esi
如果相等则直接返回True (即 1),否则将进行逐字对比,然后返回对比结果。上面的代码用C语言表述为:
{
string str1 = "strings";
string str2 = "strings";
bool isEqual = str1 == str2;
Console.WriteLine(isEqual);
}
输出的结果为:True
当我们查看IL代码的时候,内部的操作就比较清楚了:
.method public hidebysig static void Test() cil managed
{
// 代码大小 27 (0x1b)
.maxstack 2
.locals init ([0] string str1,
[1] string str2,
[2] bool isEqual)
IL_0000: ldstr "strings"
IL_0005: stloc.0
IL_0006: ldstr "strings"
IL_000b: stloc.1
IL_000c: ldloc.0
IL_000d: ldloc.1
IL_000e: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_0013: stloc.2
IL_0014: ldloc.2
IL_0015: call void [mscorlib]System.Console::WriteLine(bool)
IL_001a: ret
} // end of method Class1::Test
上面的 IL_000e 行反映了编译器在比较两个字符串时的操作,即调用了System.String类中的一个方法op_Equality(string, string)对两个字符串进行比较。
当我们深入op_Equality(string, string)方法体内的时候,我们就很清楚的知道C#比较两个字符串多的算法:
00000000 push edi
00000001 push esi
00000002 push ebx
00000003 mov edi,ecx
00000005 mov esi,edx
00000007 cmp edi,esi
00000009 jne 00000014
0000000b mov eax,1
00000010 pop ebx
00000011 pop esi
00000012 pop edi
00000013 ret
00000014 test edi,edi
00000016 je 0000001C
00000018 test esi,esi
0000001a jne 00000022
0000001c xor eax,eax
0000001e pop ebx
0000001f pop esi
00000020 pop edi
00000021 ret
00000022 mov edx,esi
00000024 mov ecx,edi
00000026 cmp dword ptr [ecx],ecx
00000028 call dword ptr ds:[79C126F4h]
0000002e movzx ebx,al
00000031 mov eax,ebx
00000033 pop ebx
00000034 pop esi
00000035 pop edi
00000036 ret
由上面的汇编代码可以看出,C#首先会比较两个字符串的地址是否相等:
00000007 cmp edi,esi
如果相等则直接返回True (即 1),否则将进行逐字对比,然后返回对比结果。上面的代码用C语言表述为:
int Equality(char*str1, char *str2)
{
if (str1 == str2) return 1;
if (str1 == null || str2 == null) return 0;
CompareString(str1, str2); // 逐个字母比较两个字符串
}
然而在Java中,通过==来判断两个字符串的做法可能会存在风险。下面的代码为Java中的比较两个字符串的代码:
class StringSample
{
public static void main(String[] args)
{
String str1 = new String("strings");
String str2 = new String("strings");
System.out.println(str1 == str2);
}
}
输出的结果为:false
为了避免这样的错误,如果我们的目的明确为了比较两个字符串是否相等,则可以通过调用equals()方法来对两个字符串对象进行比较:
System.out.println(str1.equals(str2));
输出结果:true
小结:
C#与Java在比较字符串多的时候,各自采用了不同的比较方式,在C#中,两个字符串的比较是通过调用字符串比较方法进行逐字比较,而Java中则是通过判断引用来确定两个字符串是否相等,所以当Java中的字符串对象比较时,比并不是去比较字符串对象内的字符串是否相等,而是比较两个字符串对象的引用是否相等(即是否同时指向同一个字符串空间地址)。