聊一聊C#的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。其结果就是,存储的时候你可能任性的存,在取值的时候就是你哭着找不着娘了。

好了,说了这么多你应该对这两个方法有了重新的认识了吧。如果还是不明白的话,用代码实现一下,保准明白。

原贴:http://www.cnblogs.com/xiaochen-vip8/articles/5506478.html

( 转 ) 聊一聊C#的Equals()和GetHashCode()方法的更多相关文章

  1. 聊一聊C#的Equals()和GetHashCode()方法

    博客创建一年多,还是第一次写博文,有什么不对的地方还请多多指教. 关于这次写的内容可以说是老生长谈,百度一搜一大堆.大神可自行绕路. 最近在看Jeffrey Richter的CLR Via C#,在看 ...

  2. 【转载】聊一聊C#的Equals()和GetHashCode()方法

    首先先谈一下Equals()这个方法: Equals()方法,来自于Object,是我们经常需要重写的方法.此方法的默认实现大概是这样的: public virtual bool Equals(obj ...

  3. Equals()和GetHashCode()方法深入了解

    最近在看Jeffrey Richter的CLR Via C#,在看到GetHashCode()方法的时候,有一个地方不是特别明白,就是重写Equals()方法时为什么要把GetHashCode()方法 ...

  4. 我看C#的Equals()和GetHashCode()方法

    首先先谈一下Equals()这个方法: Equals()方法,来自于Object,是我们经常需要重写的方法.此方法的默认实现大概是这样的: public virtual bool Equals(obj ...

  5. Equals Finalize GetHashCode GetType MemberwiseClone ReferenceEquals ToString String.IsInterned

    参考资料: http://blog.csdn.net/afgasdg/article/details/6889383 http://www.cnblogs.com/skyivben/archive/2 ...

  6. java重写equals和hashCode方法

    一.重写equals方法 如果不重写equals,那么比较的将是对象的引用是否指向同一块内存地址,重写之后目的是为了比较两个对象的value值是否相等. 利用equals比较八大包装对象(如int,f ...

  7. 如何编写出高质量的 equals 和 hashcode 方法?

    什么是 equals 和 hashcode 方法? 这要从 Object 类开始说起,我们知道 Object 类是 Java 的超类,每个类都直接或者间接的继承了 Object 类,在 Object ...

  8. C#中Equals和GetHashCode

    Equals和GetHashCode Equals每个实现都必须遵循以下约定: 自反性(Reflexive): x.equals(x)必须返回true. 对称性(Symmetric): x.equal ...

  9. Java中的equals和hashCode方法

    本文转载自:Java中的equals和hashCode方法详解 Java中的equals方法和hashCode方法是Object中的,所以每个对象都是有这两个方法的,有时候我们需要实现特定需求,可能要 ...

随机推荐

  1. mac 上传本地代码到 Github 教程

    网上有很多关于windows系统上传本地代码到github的文章,但是自己用的是mac,在网上也找了相关文章,实践的过程中还是遇到了很多问题,现在把自己的成功实践分享出来,希望能对大家有帮助. 1.首 ...

  2. Lintcode245 Subtree solution 题解

    [题目描述] You have two every large binary trees:T1, with millions of nodes, and T2, with hundreds of no ...

  3. 十大经典排序算法最强总结(含JAVA代码实现)

    最近几天在研究排序算法,看了很多博客,发现网上有的文章中对排序算法解释的并不是很透彻,而且有很多代码都是错误的,例如有的文章中在“桶排序”算法中对每个桶进行排序直接使用了Collection.sort ...

  4. Java虚拟机运行时栈帧结构--《深入理解Java虚拟机》学习笔记及个人理解(二)

    Java虚拟机运行时栈帧结构(周志明书上P237页) 栈帧是什么? 栈帧是一种数据结构,用于虚拟机进行方法的调用和执行. 栈帧是虚拟机栈的栈元素,也就是入栈和出栈的一个单元. 2018.1.2更新(在 ...

  5. IE常见的兼容处理

    IE常见的兼容处理 1. 禁用IE兼容模式 为了保证IE能够使用最新渲染模式而不是兼容模式,在html文档头部应加入以下代码: <head> <meta charset=" ...

  6. HashMap源码解析(JDK1.8)

    package java.util; import sun.misc.SharedSecrets; import java.io.IOException; import java.io.Invalid ...

  7. AngularJs踩过的坑

    1. 使用checkbox和radio时, 不能使用ng-model直接绑定原始对象, 需要绑定一个对象的某个子属性, 才能把值绑定到scope <label><input type ...

  8. JS基础二

    JS的实现: 核心:ECMAScript ECMAScript 并不与任何具体浏览器相绑定,实际上,它也没有提到用于任何用户输入输出的方法(这点与 C 这类语言不同,它需要依赖外部的库来完成这类任务) ...

  9. sentinel监控redis高可用集群(二)

    一.端口转发. 如果在一个主机里面,安装了两个redis实例,可以在项目里面配置IP端口,用iptables转发. iptables -t nat -A PREROUTING -p tcp --dpo ...

  10. 关于css选择器中有小数点的标签获取

    需求说明 因为项目中章节配置的时候有小数点,1,1.1,1.2,1.11的标题,这个时候每一行标题的id,class设置成标题号是独一无二的标记.但是,直接用js获取是获取不到的,例如$('#3.22 ...