Equals()和GetHashCode()方法深入了解
最近在看Jeffrey Richter的CLR Via C#,在看到GetHashCode()方法的时候,有一个地方不是特别明白,就是重写Equals()方法时为什么要把GetHashCode()方法一块重写(不重写也没关系,但是微软会发送一条警告)。在解释这个问题之前需要先把Equals()和GetHashCode()方法进行深入了解。
首先先谈一下Equals()这个方法:
Equals()方法,来自于Object,是我们经常需要重写的方法。此方法的默认实现大概是这样的:

public virtual bool Equals(object obj) { if(obj==null) return false; if(GetType() != obj.GetType()) return false; Return true; }

由此可以看出,默认的实现其实比较的是两个对象的内存地址(==操作符默认比较内存地址)。值类型和string类型除外,因为所有值类型继承于System.ValueType()(System.ValueType()同样继承于Object,但是System.ValueType()本身却是引用类型),而System.ValueType()对Equals()和==操作符进行了重写,是逐字节比较的。而string类型是比较特殊的引用类型,所以strIng在很多地方都是特殊处理的,此处就不做深究了。
Ps:按Jeffrey Richter的说法,在值类型使用Equals()时,因为Equals()使用了反射,在比较时会影响效率。
说完Equals()后再来聊一聊GetHashCode()。
其实GetHashCode()在操作值类型的时候也是被System.ValueType()重写的。经过楼主测试的几个常用值类型来看,值类型的GetHashCode()基本都是原值输出(特指整数,Int32除外),真实性有待验证。结果如下:
说完值类型,说一下引用类型,先看下面这张运行结果:
从上图的结果可以看出,虽然string是引用类型,但是只要值一样,返回的HashCode也是一样的,这取决于它的特殊性。而我们自己写的类型Coordinates同样的值但返回的HashCode却不一样,我们可以简单的理解为是coor1与coor2的内存地址不同,所以CLR认为它们是不一样的。
Ps:在程序的生命周期中,相同的对象、变量返回的HashCode是相同的,并且是唯一的。但是绝对不允许做持久性存储,程序一旦结束并重新启动后,同样的对象无法获得上次程序运行时的HashCode。
了解了两个方法后,开始今天的重点话题。
其实在上面的两个对象中(coor1、coor2),coor1.Equals(coor2)的返回结果为false(因为内存地址不同),如果我们想让它们的返回结果为true的话,只能重写Equals方法(如下图)。
重点来了,重写完Equals以后,vs发出了警告,虽然程序猿从来都是无视警告的,但这个警告确实有必要了解一下,先来看下面这三段代码。
代码段一、二:
代码段三:
看完这三段代码,应该就理解为什么要重写Equal时有必要重写GetHashCode了。
当然,如果你没打算在代码中使用Dictionary或HashTable就无所谓写不写了,换句话说,如果要把引用类型做为Dictionary或HashTable的key使用时,必须重写这两个方法。
原因:当我们把引用类型(string除外)做为Dictionary或HashTable的key时,有可能永远无法根据Key获得value的值,或者说两个类型的HashCode永远不会相等。就拿Dictionary来说,虽然我们存储的时候是键值对,但是CLR会先把key转成HashCode并且验证Equals后再做存储,根据key取值的时候也是把key转换成HashCode并且验证Equals后再取值,一定要注意验证时HashCode和Equals的关系是并且(&&)的关系。也就是说,只要GetHashCode和Equlas中有一个方法没有重写,在验证时没有重写的那个方法会调用基类的默认实现,而这两个方法的默认实现都是根据内存地址判断的,也就是说,其实一个方法的返回值永远会是false。其结果就是,存储的时候你可能任性的存,在取值的时候就是你哭着找不着娘了。
好了,说了这么多你应该对这两个方法有了重新的认识了吧。如果还是不明白的话,用代码实现一下,保准明白。
Equals()和GetHashCode()方法深入了解的更多相关文章
- ( 转 ) 聊一聊C#的Equals()和GetHashCode()方法
聊一聊C#的Equals()和GetHashCode()方法 博客创建一年多,还是第一次写博文,有什么不对的地方还请多多指教. 关于这次写的内容可以说是老生长谈,百度一搜一大堆.大神可自行绕路. ...
- 聊一聊C#的Equals()和GetHashCode()方法
博客创建一年多,还是第一次写博文,有什么不对的地方还请多多指教. 关于这次写的内容可以说是老生长谈,百度一搜一大堆.大神可自行绕路. 最近在看Jeffrey Richter的CLR Via C#,在看 ...
- 我看C#的Equals()和GetHashCode()方法
首先先谈一下Equals()这个方法: Equals()方法,来自于Object,是我们经常需要重写的方法.此方法的默认实现大概是这样的: public virtual bool Equals(obj ...
- 【转载】聊一聊C#的Equals()和GetHashCode()方法
首先先谈一下Equals()这个方法: Equals()方法,来自于Object,是我们经常需要重写的方法.此方法的默认实现大概是这样的: public virtual bool Equals(obj ...
- Equals Finalize GetHashCode GetType MemberwiseClone ReferenceEquals ToString String.IsInterned
参考资料: http://blog.csdn.net/afgasdg/article/details/6889383 http://www.cnblogs.com/skyivben/archive/2 ...
- java重写equals和hashCode方法
一.重写equals方法 如果不重写equals,那么比较的将是对象的引用是否指向同一块内存地址,重写之后目的是为了比较两个对象的value值是否相等. 利用equals比较八大包装对象(如int,f ...
- C#中Equals和GetHashCode
Equals和GetHashCode Equals每个实现都必须遵循以下约定: 自反性(Reflexive): x.equals(x)必须返回true. 对称性(Symmetric): x.equal ...
- Java中的equals和hashCode方法
本文转载自:Java中的equals和hashCode方法详解 Java中的equals方法和hashCode方法是Object中的,所以每个对象都是有这两个方法的,有时候我们需要实现特定需求,可能要 ...
- String equals()方法使用以及子串加密
String equals()方法的实现方法: 名称 说明 String.Equals (Object) 确定此 String 实例是否与指定的对象(也必须是 String)具有相同的值. Strin ...
随机推荐
- C#又能出来装个B了。一步一步微信跳一跳自动外挂
PS:语言只是载体.思维逻辑才是王道 前天看见了个python的脚本.于是装python.配置环境变量.装pip.折腾了一上午,最终装逼失败. 于是进入博客园,顶部有篇文章吸引了我 .NET开发一个微 ...
- Nginx (二) Nginx的反向代理负载均衡以及日志切割
Nginx是一个高并发,高性能的服务器,可以进行反向代理以及网站的负载均衡.这些功能的运用都在配置文件中,也就是Nginx安装目录下的conf/nginx.conf. nginx.conf 1. 先来 ...
- Angularjs 2 绝对零基础的教程(1):从安装配置开始
写在前面 适合人群: 1. 愿意未来从事前端工作,并以此开拓自己未来职业 2. 有任何一种编程语言基础 3. 喜欢简单粗暴学一门实用的技术,而不是做科研. Angular 2 比 Angular 1 ...
- qt中线程的使用方法
QT中使用线程可以提高工作效率. 要使用线程要经过一下四个步骤: (1)先创建一个c++ class文件,记得继承Thread,创建步骤如下: a.第一步 b.第二步 (2)自定义一个run函数,以后 ...
- Macaca环境配置及样例执行
1.Macaca简介 macaca是由阿里巴巴公司开发的一套自动化解决方案,适用于PC端和移动端.Macaca基于Node.js开发,测试案例编写语言暂时也只支持Node.js. 2.Macaca与A ...
- 冒烟测试与BVT测试
冒烟测试,它和回归测试的性质一样--只是一个测试活动,并不是一个测试阶段.冒烟测试贯穿于测试的任何一个阶段,单元测试.集成测试.系统测试里都有冒烟测试. 冒烟测试和其他所有的测试活动的目的不一样,它不 ...
- 字符串匹配KMP算法的C语言实现
字符串匹配是计算机的基本任务之一. 举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD" ...
- K:枚举的线程安全性及其序列化问题
枚举是如何保证线程安全的且其在序列化和反序列化的操作中是单例的? 要想看源码,首先得有一个类吧,那么枚举类型到底是什么类呢?是enum吗?答案很明显不是,enum就和class一样,只是一个关 ...
- thinkphp 官方文件执行引入流程
官方手册上的执行流程图: 系统流程 用户URL请求 调用应用入口文件(通常是网站的index.php) 载入框架入口文件(ThinkPHP.php) 记录初始运行时间和内存开销 系统常量判断及定义 载 ...
- Debian安装fail2ban来防止扫描
vps的root密码不要设置的太简单,这样很容易被攻破,你可以安装如下软件来降低vps被攻破的机会. 输入如下命令: apt-get install fail2ban 提示如下表示安装完成: root ...