判断是否为同一对象
普通的引用类型比较:
1 //运行结果都是false,这个没有要说明的,因为p1跟p2存储的指向堆中的实例地址不一样.不是同一个对象 2 Person p1 = new Person 3 { 4 Name = "XXX", 5 Age = 18, 6 Email = "XXX@yahoo.com" 7 }; 8 9 Person p2 = new Person 10 { 11 Name = "XXX", 12 Age = 18, 13 Email = "XXX@yahoo.com" 14 }; 15 //p2 = p1; 16 Console.WriteLine(p1 == p2); 17 Console.WriteLine(p1.Equals(p2)); 18 Console.WriteLine(ReferenceEquals(p1, p2)); 19 Console.ReadKey();
String类型比较:
1 string s1 = "abc"; 2 string s2 = "abc"; 3 Console.WriteLine(s1 == s2); 4 Console.WriteLine(s1.Equals(s2)); 5 Console.WriteLine(ReferenceEquals(s1, s2)); 6 Console.ReadKey();
运行结果都是true,是怎么回事呢?对于字符串类型来说,重载了Equals()方法,在这个重载的方法中其实是判断的两个字符串中的字符是否完全一样,如果一样就返回true,并不是判断两个对象是否为同一个对象。
== 这个操作符进行了重载,在该重在函数中也是对字符的内容作了判断,所以 == 表现出了与Equals()同样的效果。但是ReferenceEquals方法不是验证是否未同一对象吗?难道s1跟s2所指向堆中的地址相同?
我们看下即时窗口中s1跟s2所指向的地址;
事实的确这样,因为字符串不可变性,公共语言运行库会自动维护一个名为“拘留池”(intern pool) 的表,默认只有代码中写的字面才会进入字符串拘留池,动态字符串(变量)默认是不在字符串拘留池中的,上面的s1="abc",abc就是代码中写的字面。因此,具有特定值的字符串的实例在系统中
只有一个,所指向的地址是一样的,要是这样声明s1跟s2,第三个问题就是false,
string s1 = new string(new char[] { 'a', 'b', 'c' });
string s2 = new string(new char[] { 'a', 'b', 'c' });
在扩展一下拘留池:
string a = "a";
string b = "b";
string c = "c";
string s1 = "abc";
string s2= "a" + "b" + "c";//反编译后直接就是string s2; s2="abc";,也就是字面
string s3 = a + b + c;//反编译后是调用string.Concat方法动态连接这几个对象;是动态字符串;
所以s2和s3不是同一对象;
总结:使用object.ReferenceEquals()可以始终准确验证两个变量是否为同一个对象。