C#中相等的判断
我主要是用例子来说明一下问题:
首先说明一下string字符串,string它是一个引用类型的,只不过是它拥有了值类型的特征,
而通过书中的介绍
ReferenceEquals方法不能继承,它用来专门比较引用类型是否相等,所以它是比较引用的首选,有了它我们可以毫无顾虑的判断,并且简单,看例子:
上面的例子再次可以证明既然它能比较出连个字符串是否相等,就证明字符串肯定是引用类型,
再者如果比较字符串str1与str2,答案是不相等,因为str2新建了一个对象(new),所以两者不存在引用关系,
肯定是false,而我们再次再介绍一下,看了源码我发现string类没有重写“+"这个运算符号,所以我们在利用字符串进行相加时,只是单纯意义上的字符连接,可能不会像java一样每加一次会创建新对象,于是当我们进行字符串a和b进行比较时,会发现仍然相等,所以说明两者出于同一个对象,大家还有疑问时我们对字符串进行直接复制,就会new对象呢?答案是不会,看了java对此的解释,通常字符串有一个STRING池.当我们进行字符串直接复制时,都会通过这个string池,如果在string池中找到已有的字符串,那么就指向同一个字符串地址,与我们new一个string类是完全不一样。
继续介绍
equal和==在自定义类型是ValueType的时候要改写
当自定义类型是ReferenceType的时候,如果想改变RefrenceType默认的用对象标志判
等的方式,可以改写equal
当自定义类型是RefrenceType的时候,最好不要改写operator==.
还有需要注意的是==比较对于非自定义的值类型就是比较值得大小,
而对于比较引用类型,就是比较是否出自由同一个对象,
对于自定义的值类型如struct可以自己来重写,
对于自定义的引用类型class最好不要用来重写,
并且重写了==就需要重写!=还要重写equal,如果重写了equal就需要重写GetHashCode方法,
因为两者要相等就必须该方法返回值要相等。
注意我上面的例子定义了两个重写equal,用第一个的话为false因为它调用了==比较,我们介绍过==比较对象时是要比较两个是否出于一个对象,显然不是。加上这句acar=bcar;结果就是相等了。
再看第二种方法,因为我们是自定义的类,所以我们根据我们的需求判断两个对象相等的条件,这里我们选择speed,只要两个对象speed相等我们就判断这两个对象是相等的。
具体实现看代码大家已经八九不离十了,而大家看了我重写的GetHashCode(),里面返回speed,这点需要说明的是,我提过重写equal必须要重写该方法要返回一样的值,那这个值什么?这里我选择了speed,当然我这个写法太简单了,对于重写GetHashCode()的规则很多,但道理都是一样的那就是:相等的对象必须返回相同的GetHashCode(),这个时候你就可以定里面返回的东西啦。
对于equal在比较非自定义的值类型时与==相同,
对比较引用类型的时候也是判断是否出于同一个对象,
下面我们接着介绍string,
既然string是引用类型,那
命名str1和str2不是同一个引用(前面已经介绍),但为什么后面的比较确相等呢?
我们看源代码可知道string它重写了==和equal这两个方法,我们不追究里面的实现,
但至少它里面的实现应该是和我们前面提到的speed比较相似,并没有比较对象的引用,
而是比较对象的值。
首先说明一下string字符串,string它是一个引用类型的,只不过是它拥有了值类型的特征,
而通过书中的介绍
ReferenceEquals方法不能继承,它用来专门比较引用类型是否相等,所以它是比较引用的首选,有了它我们可以毫无顾虑的判断,并且简单,看例子:
using System;
using System.Collections.Generic;
using System.Text;
namespace fanxing
{
class Class4
{
}
class Application2
{
static void Main(string[] args)
{
Class4 aclass4 = new Class4();
Class4 bclass4 = new Class4();
//bclass4=aclass4; 这里加了注释,去掉注释后比较的结果完全不一样
if (Object.ReferenceEquals(aclass4, bclass4))
{
Console.Write(aclass4.GetHashCode() + "===" + bclass4.GetHashCode());
}
else
{
Console.Write("false");
}
int a=5;
int b=5;
if (Object.ReferenceEquals(a, b)) //这里比较值类型,所以肯定是false毫无疑问,它不是用来比较值类型的
{
Console.Write(a.GetHashCode() + "===" + b.GetHashCode());
}
else
{
Console.Write("false");
}
char[] c1 = new char[] { 'a', 'a', 'a' };
char[] c2 = new char[] { 'a', 'a', 'a' };
string str1 = "aaa";
String a = "12345";
String b = "";
String c = "12345";
b = b + '1';
b = b + '2';
b = b + '3';
b = b + '4';
b = b + '5';
string str2 = new String(c1);
string str3 = str2;
string str4 = "aaa";
//int aaa = 5;
//int bbb = 5;
if (Object.ReferenceEquals(a, c)) //比较字符串,已经介绍过字符串是特殊的引用类型
{
Console.Write(str3.GetHashCode() + "===" + str2.GetHashCode());
}
else
{
Console.Write("false");
}
Console.Read();
}
}
}
using System.Collections.Generic;
using System.Text;
namespace fanxing
{
class Class4
{
}
class Application2
{
static void Main(string[] args)
{
Class4 aclass4 = new Class4();
Class4 bclass4 = new Class4();
//bclass4=aclass4; 这里加了注释,去掉注释后比较的结果完全不一样
if (Object.ReferenceEquals(aclass4, bclass4))
{
Console.Write(aclass4.GetHashCode() + "===" + bclass4.GetHashCode());
}
else
{
Console.Write("false");
}
int a=5;
int b=5;
if (Object.ReferenceEquals(a, b)) //这里比较值类型,所以肯定是false毫无疑问,它不是用来比较值类型的
{
Console.Write(a.GetHashCode() + "===" + b.GetHashCode());
}
else
{
Console.Write("false");
}
char[] c1 = new char[] { 'a', 'a', 'a' };
char[] c2 = new char[] { 'a', 'a', 'a' };
string str1 = "aaa";
String a = "12345";
String b = "";
String c = "12345";
b = b + '1';
b = b + '2';
b = b + '3';
b = b + '4';
b = b + '5';
string str2 = new String(c1);
string str3 = str2;
string str4 = "aaa";
//int aaa = 5;
//int bbb = 5;
if (Object.ReferenceEquals(a, c)) //比较字符串,已经介绍过字符串是特殊的引用类型
{
Console.Write(str3.GetHashCode() + "===" + str2.GetHashCode());
}
else
{
Console.Write("false");
}
Console.Read();
}
}
}
再者如果比较字符串str1与str2,答案是不相等,因为str2新建了一个对象(new),所以两者不存在引用关系,
肯定是false,而我们再次再介绍一下,看了源码我发现string类没有重写“+"这个运算符号,所以我们在利用字符串进行相加时,只是单纯意义上的字符连接,可能不会像java一样每加一次会创建新对象,于是当我们进行字符串a和b进行比较时,会发现仍然相等,所以说明两者出于同一个对象,大家还有疑问时我们对字符串进行直接复制,就会new对象呢?答案是不会,看了java对此的解释,通常字符串有一个STRING池.当我们进行字符串直接复制时,都会通过这个string池,如果在string池中找到已有的字符串,那么就指向同一个字符串地址,与我们new一个string类是完全不一样。
继续介绍
equal和==在自定义类型是ValueType的时候要改写
当自定义类型是ReferenceType的时候,如果想改变RefrenceType默认的用对象标志判
等的方式,可以改写equal
当自定义类型是RefrenceType的时候,最好不要改写operator==.
还有需要注意的是==比较对于非自定义的值类型就是比较值得大小,
而对于比较引用类型,就是比较是否出自由同一个对象,
对于自定义的值类型如struct可以自己来重写,
对于自定义的引用类型class最好不要用来重写,
并且重写了==就需要重写!=还要重写equal,如果重写了equal就需要重写GetHashCode方法,
因为两者要相等就必须该方法返回值要相等。
using System;
using System.Collections.Generic;
using System.Text;
namespace fanxing
{
class car
{
private int speed;
private int num;
public car(int speed,int num)
{
this.speed = speed;
this.num=num;
}
/*public override bool Equals(object x)
{
if (!(x is car))
{
return false;
}
else
{
return this == x as car;
}
}*/
public override bool Equals( object right )
{
if (right == null)
return false;
if (object.ReferenceEquals( this, right ))
return true;
if (this.GetType() != right.GetType())
return false;
return CompareFooMembers(
this, right as car );
}
public bool CompareFooMembers(car aaa,car bbb)
{
if (aaa.speed == bbb.speed)
{
return true;
}
else
{
return false;
}
}
public override int GetHashCode()
{
return speed;
}
}
class Application1
{
static void Main(string[] args)
{
car acar =new car(500,5);
car bcar = new car(500,9);
if (acar.Equals(bcar))
{
Console.Write(acar.GetHashCode() + "----" + bcar.GetHashCode());
}
else
{
Console.Write("false");
}
Console.Read();
}
}
}
using System.Collections.Generic;
using System.Text;
namespace fanxing
{
class car
{
private int speed;
private int num;
public car(int speed,int num)
{
this.speed = speed;
this.num=num;
}
/*public override bool Equals(object x)
{
if (!(x is car))
{
return false;
}
else
{
return this == x as car;
}
}*/
public override bool Equals( object right )
{
if (right == null)
return false;
if (object.ReferenceEquals( this, right ))
return true;
if (this.GetType() != right.GetType())
return false;
return CompareFooMembers(
this, right as car );
}
public bool CompareFooMembers(car aaa,car bbb)
{
if (aaa.speed == bbb.speed)
{
return true;
}
else
{
return false;
}
}
public override int GetHashCode()
{
return speed;
}
}
class Application1
{
static void Main(string[] args)
{
car acar =new car(500,5);
car bcar = new car(500,9);
if (acar.Equals(bcar))
{
Console.Write(acar.GetHashCode() + "----" + bcar.GetHashCode());
}
else
{
Console.Write("false");
}
Console.Read();
}
}
}
注意我上面的例子定义了两个重写equal,用第一个的话为false因为它调用了==比较,我们介绍过==比较对象时是要比较两个是否出于一个对象,显然不是。加上这句acar=bcar;结果就是相等了。
再看第二种方法,因为我们是自定义的类,所以我们根据我们的需求判断两个对象相等的条件,这里我们选择speed,只要两个对象speed相等我们就判断这两个对象是相等的。
具体实现看代码大家已经八九不离十了,而大家看了我重写的GetHashCode(),里面返回speed,这点需要说明的是,我提过重写equal必须要重写该方法要返回一样的值,那这个值什么?这里我选择了speed,当然我这个写法太简单了,对于重写GetHashCode()的规则很多,但道理都是一样的那就是:相等的对象必须返回相同的GetHashCode(),这个时候你就可以定里面返回的东西啦。
对于equal在比较非自定义的值类型时与==相同,
对比较引用类型的时候也是判断是否出于同一个对象,
下面我们接着介绍string,
既然string是引用类型,那
using System;
using System.Collections.Generic;
using System.Text;
namespace fanxing
{
class Class4
{
}
class Application2
{
static void Main(string[] args)
{
char[] c1 = new char[] { 'a', 'a', 'a' };
char[] c2 = new char[] { 'a', 'a', 'a' };
string str1 = "aaa";
String a = "12345";
String b = "";
String c = "12345";
b = b + '1';
b = b + '2';
b = b + '3';
b = b + '4';
b = b + '5';
string str2 = new String(c1);
string str3 = str2;
string str4 = "aaa";
int aaa = 5;
int bbb = 5;
if (Object.ReferenceEquals(a,b))
{
Console.Write(str3.GetHashCode()+"==="+str2.GetHashCode());
}
else
{
Console.Write("false");
}
if (str1 == str2)
{
Console.Write("true");
}
else
{
Console.Write("false");
}
if (aaa.Equals(bbb))
{
Console.Write("true");
}
else
{
Console.Write("false");
}
Console.Read();
}
}
}
using System.Collections.Generic;
using System.Text;
namespace fanxing
{
class Class4
{
}
class Application2
{
static void Main(string[] args)
{
char[] c1 = new char[] { 'a', 'a', 'a' };
char[] c2 = new char[] { 'a', 'a', 'a' };
string str1 = "aaa";
String a = "12345";
String b = "";
String c = "12345";
b = b + '1';
b = b + '2';
b = b + '3';
b = b + '4';
b = b + '5';
string str2 = new String(c1);
string str3 = str2;
string str4 = "aaa";
int aaa = 5;
int bbb = 5;
if (Object.ReferenceEquals(a,b))
{
Console.Write(str3.GetHashCode()+"==="+str2.GetHashCode());
}
else
{
Console.Write("false");
}
if (str1 == str2)
{
Console.Write("true");
}
else
{
Console.Write("false");
}
if (aaa.Equals(bbb))
{
Console.Write("true");
}
else
{
Console.Write("false");
}
Console.Read();
}
}
}
命名str1和str2不是同一个引用(前面已经介绍),但为什么后面的比较确相等呢?
我们看源代码可知道string它重写了==和equal这两个方法,我们不追究里面的实现,
但至少它里面的实现应该是和我们前面提到的speed比较相似,并没有比较对象的引用,
而是比较对象的值。