c# 关于相等判断
来源:互联网 发布:jquery mobileui 知乎 编辑:程序博客网 时间:2024/06/04 18:35
今天介绍一下关于相等的判断,这应该是个基础的东西,但是又有很多值得深入研究的东西,
基本概念的东西太多,这个大家可以去查资料,
http://book.csdn.net/bookfiles/295/10029512576.shtml
通过这一节就已经可以对这几种方法有大体了解,再次不做介绍,
我主要是用例子来说明一下问题:
首先说明一下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比较相似,并没有比较对象的引用,
而是比较对象的值,再次介绍完了,这两天不停的在写,其实也是对自己以后看起来比较容易,主要是对自己方便,写的乱了点,顺便总结一下,希望看到的朋友感觉有什么地方不对,可以指出。
补充
通过编译我们可以看到具体的字符串相加“+”的编译过程,具体通过调用静态方法System.String::Concat来实现,所以看下面的例子的结果也就明白了
基本概念的东西太多,这个大家可以去查资料,
http://book.csdn.net/bookfiles/295/10029512576.shtml
通过这一节就已经可以对这几种方法有大体了解,再次不做介绍,
我主要是用例子来说明一下问题:
首先说明一下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比较相似,并没有比较对象的引用,
而是比较对象的值,再次介绍完了,这两天不停的在写,其实也是对自己以后看起来比较容易,主要是对自己方便,写的乱了点,顺便总结一下,希望看到的朋友感觉有什么地方不对,可以指出。
补充
using System;
using System.Collections.Generic;
using System.Text;
namespace fanxing
{
class Application333
{
static void Main(string[] args)
{
string a = "aaa";
String str1 = "b";
string b = str1 + "cc";
string c = "d" + "ee";
Console.Read();
}
}
}
using System.Collections.Generic;
using System.Text;
namespace fanxing
{
class Application333
{
static void Main(string[] args)
{
string a = "aaa";
String str1 = "b";
string b = str1 + "cc";
string c = "d" + "ee";
Console.Read();
}
}
}
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// 代码大小 38 (0x26)
.maxstack 2
.locals init ([0] string a,
[1] string str1,
[2] string b,
[3] string c)
IL_0000: nop
IL_0001: ldstr "aaa"
IL_0006: stloc.0
IL_0007: ldstr "b"
IL_000c: stloc.1
IL_000d: ldloc.1
IL_000e: ldstr "cc"
IL_0013: call string [mscorlib]System.String::Concat(string,
string)
IL_0018: stloc.2
IL_0019: ldstr "dee"
IL_001e: stloc.3
IL_001f: call int32 [mscorlib]System.Console::Read()
IL_0024: pop
IL_0025: ret
} // end of method Application333::Main
{
.entrypoint
// 代码大小 38 (0x26)
.maxstack 2
.locals init ([0] string a,
[1] string str1,
[2] string b,
[3] string c)
IL_0000: nop
IL_0001: ldstr "aaa"
IL_0006: stloc.0
IL_0007: ldstr "b"
IL_000c: stloc.1
IL_000d: ldloc.1
IL_000e: ldstr "cc"
IL_0013: call string [mscorlib]System.String::Concat(string,
string)
IL_0018: stloc.2
IL_0019: ldstr "dee"
IL_001e: stloc.3
IL_001f: call int32 [mscorlib]System.Console::Read()
IL_0024: pop
IL_0025: ret
} // end of method Application333::Main
using System;
using System.Collections.Generic;
using System.Text;
namespace fanxing
{
class Application333
{
static void Main(string[] args)
{
string a = "aaa";
String str1 = "a";
string b = str1 + "aa";//动态生成的字符串,所以不放入散列中,ReferenceEquals比较为false
string c = "a" + "aa";//由于都是字符串常量所以会在散列表中查找相应的字符串,找到即位true
string d = string.Intern(b);//利用intern可以将动态生成的字符串放入散列当中,ReferenceEquals为true
if (Object.ReferenceEquals(a,d))
{
Console.Write("true");
}
else
{
Console.Write("false");
}
if (a == b)
{
Console.Write("aa");
}
else
{
Console.Write("bb");
}
Console.Read();
}
}
}
using System.Collections.Generic;
using System.Text;
namespace fanxing
{
class Application333
{
static void Main(string[] args)
{
string a = "aaa";
String str1 = "a";
string b = str1 + "aa";//动态生成的字符串,所以不放入散列中,ReferenceEquals比较为false
string c = "a" + "aa";//由于都是字符串常量所以会在散列表中查找相应的字符串,找到即位true
string d = string.Intern(b);//利用intern可以将动态生成的字符串放入散列当中,ReferenceEquals为true
if (Object.ReferenceEquals(a,d))
{
Console.Write("true");
}
else
{
Console.Write("false");
}
if (a == b)
{
Console.Write("aa");
}
else
{
Console.Write("bb");
}
Console.Read();
}
}
}
- c# 关于相等判断
- C#判断对象相等
- 关于判断C#的两个string是否相等的问题
- C# 判断对象是否相等
- 关于Long类型相等判断
- c# 相等判断之间的关系
- C#如何判断两个日期是否相等
- C#中判断字符串相等的方法
- C#中的相等性判断(RefrenceEquals、Equals)
- C#判断两个对象是否相等
- c# 判断相等常量放前面
- java中关于字符串相等判断
- 关于判断字符串是否相等的问题
- 关于两Integer是否相等的判断
- 关于integer和int判断相等
- 相等判断
- 逐步认识C#四种判断相等的方法
- 认识C#四种判断相等的方法
- 朋友,快乐与痛苦
- 雨天
- C++实现语音聊天
- VC动态内存大小信息的存放位置
- 开销(Overhead)究竟是什么?
- c# 关于相等判断
- 原版软件工程图书阅读指南
- 茉莉清茶
- 企业项目管理软件介绍
- 项目管理-计划-目标范围确定
- 学会感恩
- [转贴]系统架构师是怎样炼成的?
- 软件开发项目计划编制过程
- 简单了解Timer与TimerTask