zoukankan      html  css  js  c++  java
  • 在对象比较中,对象相等和对象一致分别指的是什么?

    对象数据存内存堆里,对象一致即内存堆相同,对象相等为哈希表中键同值可能不同

    简单的讲:相等性(quality)就是两个对象,它们的值相等。同一性(identity)就是指引用的是否为同一个对象。 下面是我的读书笔记: C# 中有两种不同的相等:引用相等和值相等。值相等是大家普遍理解的意义上的相等:它意味着两个对象包含相同的值。例如,两个值为 2 的整数具有值相等性。

    引用相等意味着要比较的不是两个对象,而是两个对象引用,这两个对象引用所引用的是同一个对象。我们这里把值相等叫做对象的“相等性(equality)”,把引用相等叫做对象的同一性(identity)。

    我们都知道在System.Object类型中提供了一个名为Equals的虚方法,它的作用是在两个对象相等的情况下返回true,不相等时返回false。等等,这里的说的“相等”是哪个?是“相等性(equality)”还是“同一性(identity)”。

    好吧,来看一下代码吧,System的Object方法是像下面这样实现的:

    public class Object { public virtual Boolean Equals(Object obj)

    {

          // 如果两个引用指向的是同一个对象,那么它们肯定相等

         if (this == obj) return true;

        // 假定对象不相等

        return false;

    }

    }

    表明上看它好像是实现的很合理:

    假如this和Obj引用同一对象,自然就是true了,因为Equals知道一个对象肯定等于它自身。

    然而,如果this和Obj引用不同的对象哪?,Equals就不能肯定对象是否包含相同的值,

    所以总结一句话就是:Object的Equals方法实现的只是“同一性(identity)”,而不是“相等性(equality)”。

    多么的令人遗憾啊~!Object的Equals的默认实现并不合理,既然不合理我们就来重写它吧,先来看看如何在内部正确实现一个Equals方法(我把它概括为四个字——空、型、值、基):

    如果obj参数为null,就返回false;

    如果this和obj参数引用不同的类型对象,返回false;

    针对类型定义的每个实例字段,将this对象的值和obj对象的值进行对比,任何字段不相等,就返回false;

    调用基类的Equals方法,以便比较它定义的任何字段。如果基类的Equals方法返回false,就返回false;否则返回true;

    再来看一下Object的Equals方法的实现代码:

        public class Object

       {

            public virtual Boolean Equals(Object obj)

            {

                 if (obj == null)

                 return false;

                if (this.GetType() != obj.GetType())

                return false;

               // 如果对象属于相同的类型,那么在它们的多有字段都匹配的前提下返回true

              // 由于System.Object没有定义任何字段,所以字段是匹配的

              return true;

           }

    }  

    其实,这里要说一下,Microsoft并没有这样去实现他的代码,而是要比这个复杂的多的多。

     那么Equals方法可以在子类中重写,那么就不可以用Equals方法来测试同一性(identity)了。怎么办啊?

    Microsoft在Object中提供了一个静态方法ReferenceEquals,其原型如下:

    public class Object

    {

      public static Boolean ReferenceEquals(Object objA, object objB)

      {

      return (objA == objB);

      }

    }

    注意了啊,如果想要检查同一性(identity),那么务必调用ReferenceEquals,而不应该使用C#的==操作符(除非事先把它们转化为Object类型),

    原因是其中某个操作数的类型可能重载了==操作符,为其赋予了其它语义。

    另外,System.ValueType重写了Object的Equals方法。并进行了正确的实现来执行相等性(equality)检查,而不是同一性(identity)检查。

    在内部,ValueType的Equals方法是像这样实现的:

      如果obj参数为null,返回false; 如果this和obj引用的不同类型的对象,返回false;

      针对类型定义的每个实例字段,都将this对象的值和obj对象中的值进行比较。

      如果有字段不相等,就返回false; 返回true;

      ValueType的Equals的方法不会调用Object的Equals方法。

      顺便说一下,ValueType的Equals方法是通过反射技术来完成的。由于CLR反射机制较慢,所以在定义自己的值类型时,应该重写Equals方法,并提供自己的实现,以便提高性能。当然在自己的实现中不要调用base.Equals。

       要重写Equals,必须遵循一下几点特性: x.Equals(x) 返回 true。 (自反性) x.Equals(y) 与 y.Equals(x) 返回相同的值。 (对称性) 如果 (x.Equals(y) && y.Equals(z)) 返回 true,则 x.Equals(z) 返回 true。 (传递性) 只要不修改 x 和 y 所引用的对象,x.Equals(y) 的后续调用就返回相同的值。 (一致性) x.Equals(null) 返回 false。

      对象们都住在不同的房间里,每个房间只能住一个对象.对象们都被锁在房间里,永远没有办法搬家(至少从我们讨论的角度来说,这个说法是正确的).所以如果你知道了一个对象的

    房间号,就能找到对应的对象. 现在假如我们有两张名片,上面如果写着相同的房间号,我们就可以断定,这两张名片是同一个对象分发出来的,这就是同一性,也就是你所说的一致. 假如1

    号房里住着一个值为1的整数对象, 2号房里住着另一个值为2的整数对象,3号房里住着另另一个值为1的整数对象.我们又有它们各自的一张名片, 那么,第一个名片和第三个对应的对

    象的值是相等的,但是它们不是同一个对象,用你的词来说,也就是说它们"相等",但不"一致". 如果上面说得太清楚了,那么这里让你再困扰一会吧,哈哈: 这里的名片就是引用(i, count

    之类的变量/字段等的名称); 房间所在的大楼就是内存,房间号就是内存地址. 对象就是内存里保存的数据.

      对象们都住在不同的房间里,每个房间只能住一个对象.对象们都被锁在房间里,永远没有办法搬家(至少从我们讨论的角度来说,这个说法是正确的).所以如果你知道了一个对象的房间号,就能找到对应的对象.

    现在假如我们有两张名片,上面如果写着相同的房间号,我们就可以断定,这两张名片是同一个对象分发出来的,这就是同一性,也就是你所说的一致.


    假如1号房里住着一个值为1的整数对象, 2号房里住着另一个值为2的整数对象,3号房里住着另另一个值为1的整数对象.我们又有它们各自的一张名片, 那么,第一个名片和第三个对应的对象的值是相等的,但是它们不是同一个对象,用你的词来说,也就是说它们相等,但不一致.


    如果上面说得太清楚了,那么这里让你再困扰一会吧,哈哈:


    这里的名片就是引用(i, count之类的变量/字段等的名称);


    房间所在的大楼就是内存,房间号就是内存地址.对象就是内存里保存的数据.
  • 相关阅读:
    使用vscode 用git 拉取代码,提示:在签出前,请清理存储库工作树
    区分手机端和pc端加载不同的样式
    关于vue的代码规范
    各种名词汇总整理
    ZB埋点汇总
    项目实战 OLAP数据提取
    大数据intern_1总结:数据埋点以及SQL复习
    leetcode 343+279+91+64+70 动态规划
    leetcode 241 加优先级括号
    leetcode 17+79+93+46+47+77+39+40+78+90+131+37 回溯法
  • 原文地址:https://www.cnblogs.com/Mryang-blog-cn/p/CsharpObjectCompare.html
Copyright © 2011-2022 走看看