• 学习笔记Equal()方法、ReferenceEqual()方法以及运算符==的区别


    看到这个问题是在做一道java考试题时看到的, 我当时认为这个java题目的答案在C#中也是成立的。说来也奇怪,不知道从何时起养成的习惯,学东西总觉得还是再确认一下比较好,结果一确认问题一大堆……。网上搜了些文章看了看,还是有点模糊,最终MSDN是个好东西呀,什么时候一出问题想到的是MSDN而不是谷歌或百度,我估计我就又成长一步了,啰嗦这么多,结论——MDSN很重要

    ReferenceEquals()和Equals()方法在MSDN中的解释:

    C# 中有两种不同的相等:引用相等和值相等。值相等是大家普遍理解的意义上的相等:它意味着两个对象包含相同的值。例如,两个值为 2 的整数具有值相等性。引用相等意味着要比较的不是两个对象,而是两个对象引用,且两者引用的是同一个对象。这可以通过简单的赋值来实现,如下面的示例所示:

    代码
    System.Object a = new System.Object();
    System.Object b
    = a;
    System.Object.ReferenceEquals(a, b);
    //returns true


    //这里稍作更改,以证明Equals和ReferenceEquals的结果:

    Console.WriteLine(System.Object.ReferenceEquals(a, b).ToString());
    //returns true

    System.Object c
    = new System.Object();
    System.Object d
    = new System.Object();
    c
    = (object)100;
    d
    = (object)100;

    Console.WriteLine(System.Object.Equals(c,d).ToString());
    //returns true
    Console.WriteLine(System.Object.ReferenceEquals(c,d).ToString()); //returns false
     

    在上面的代码中,只存在一个对象,但存在对该对象的多个引用:a 和 b。由于它们引用的是同一个对象,因此具有引用相等性。如果两个对象具有引用相等性,则它们也具有值相等性,但是值相等性不能保证引用相等性 (修改代码以证明) 。若要检查引用相等性,应使用 ReferenceEquals。若要检查值相等性,请使用 Equals。

    Equals()方法在MSDN中的参考:

    Equals 的默认实现仅支持引用相等,但派生类可重写此方法以支持值相等。

    对于引用类型,相等定义为对象相等,即这些引用是否引用同一对象。对于值类型,相等定义为按位相等。ValueType 类支持值类型。

    代码
    using System;

    public class Sample
    {
    void Method()
    {
    Object Obj1
    = new Object();
    Object Obj2
    = new Object();
    Console.WriteLine(Obj1.Equals(Obj2));
    //===> false
    Obj2 = Obj1;
    Console.WriteLine(Obj1.Equals(Obj2));
    //===> true

    //这里稍作更改,以证明值类型下的Equals方法:
    char c1 = 'A';
    char c2 = 'A';
    Console.WriteLine(c1.Equals(c2));
    //===> true

    Obj1
    = 'A';
    Obj2
    = 'A';
    Console.WriteLine(Obj1.Equals(Obj2).ToString());
    //===> true, 这里为子类实例指向父类的引用(多态性),实际上这里调用的子类的Equals()方法,即值类型的Equals方法

    }
    }

    在默认情况下Equals只能在引用类型中用,但是在ValueType类型中已经重写了Equals方法,所以通常情况下Equals方法既可以用于引用类型,也可以应用于值类型;在引用类型中Equals方法比较的是引用相等,而在值类型中Equals方法比较的是值相等。

     

    ==运算符在MSDN中的解释:

    对于预定义的值类型,如果操作数的值相等,则相等运算符 (==) 返回 true,否则返回 false。对于 string 以外的引用类型,如果两个操作数引用同一个对象,则 == 返回 true。对于 string 类型,== 比较字符串的值。

    代码
    // cs_operator_equality.cs
    using System;
    class MainClass
    {
    static void Main()
    {
    // Numeric equality: True
    Console.WriteLine((2 + 2) == 4);//return true,这里比较的是值相等

    // Reference equality: different objects,
    // same boxed value: False.
    object s = 1;
    object t = 1;
    Console.WriteLine(s
    == t);//return false,这里比较的是引用相等
    Console.WriteLine(s.Equals(t).ToString());//return true,这里比较的是值相等(多肽)


    // Define some strings:
    string a = "hello";
    string b = String.Copy(a); //注意:这里的Copy方法将在堆中创建一个新对象, 并将a的值拷贝到b中,也就是说a,b的值虽然相同,但是引用却不相同,a和b是不同的对象
    string c = "hello"; //注意:这的操作设计到string的一个优化策略,对于string类型的两个变量a和c,如果系统发现a和c的内容相同,则直接将a的引用赋给c;也就是说a和c的引用指向的是同一对象。(相同的引用肯定有相同的值,但是相同值却不一定有相同的引用)

    // Compare string values of a constant and an instance: True
    Console.WriteLine(a == b);//return true,string比较特殊,string的很多方法被重写过, 这里比较的是值相等,即内容相等
    Console.WriteLine(a.Equals(b) .ToString()); //return true,这里比较的是值相等,Equals()方法是string上的方法

    // Compare string references;
    // a is a constant but b is an instance: False.
    Console.WriteLine((object)a == (object)b);//return false,这里比较的是引用相等,因为string的==操作被重写过,所以强转为object类型后再比较其引用。因为b创建新的对象, 所以虽然a和b的值相同,但终究是不同的引用
    Console.WriteLine((object)a.Equals((object)b) .ToString()); //return true,这里比较的是值相等, Equals()方法是string上的方法(多肽)

    // Compare string references, both constants
    // have the same value, so string interning
    // points to same reference: True.
    Console.WriteLine((object)a == (object)c);//return true,这里的a和c的值相同,那么编译器认为a和c指向同一个引用
    Console.WriteLine((object)a.Equals((object)c) .ToString()); //return true,这里比较的是值相等,Equals()方法是string上的方法(多肽)
    }
    }

    string类型比较特殊,因为string类型的使用非常频繁,所以作为引用类型的string的很多方法都被重写过,以至于我们可以像使用值类型一样来使用string类型。

     

    综上所述:

    对于引用类型来说,java中的==比较的是引用,而Equals方法比较的是值(只为了考试而了解java,我个人不熟悉java,对真实情况不太确定。但至少那道题目的答案是这个意思)。

     

    在.NET中,ReferenceEquals()方法是专门用来表示引用相等的;

    ==运算符和Equals()方法都可以用来表示引用相等和值相等。对于值类型而言, ==和Equals()方法是一样的,使用上没有什么区别。那么重点是引用类型:

    从效果上说,对于引用类型, ==运算符表示引用相等(string有运算符重载,除外),而Equals()表示值相等。从效果上讲,这个说法好像不算错,网上也有这么一种说法。

     

    从原理上说,无论是对值类型还是对于引用类型,==运算符和Equals()方法是相同的,当然排除了一个是运算符一个是方法的这个区别。为什么这样说呢?对于值类型而言,==运算符表示值相等,而Equals()方法在绝大多数的值类型中都重写了这个方法,使之能够支持值类型。在值类型这个层面的区别基本可以忽略。而对于引用类型而言, ==运算符表示引用相等(string除外),Equals()默认只支持引用类型(见第二个代码块),也表示引用相等。因此有==运算符既支持引用相等,也支持值相等,同样Equals()方法也支持值相等和引用相等, 所以==运算符和Equals()方法是相同的。那么为什么第三个代码块中的==运算符和Equals()方法的结果屡有不同呢?答案是多肽:子类实例指向父类引用,同种语义不同行为。虽然object为引用类型,而引用类型的Equals()方法的结果应该是引用相等,但由于多肽的存在,object类型的变量中实际存放的是值类型,所以调用的Equals()方法是子类实例的,因此才体现不相等的结果。也正因为如此,值相等还是引用相等和多肽这两个不相干的问题,硬是被说成了==运算符是引用相等而Equals()方法是值相等。

     

    个人认为:==运算符和Equals()方法除了运算符和方法的区别外,再没有别的区别。而所谓的Equals()方法表示值相等的说法只是由于多肽而造成的假象。当然,Equals()用于值相等的说法效果上好像也说得过去。

  • 相关阅读:
    ld: symbol(s) not found for architecture arm64
    一个好玩的命令
    统计代码行数命令
    【转】 C语言自增自减运算符深入剖析
    gcc 生成动态库时-fpic选项是什么意思。
    每天一条linux命令——halt
    每天一条linux命令——shutdown
    推荐一些编程学习的网站
    每天一条linux命令——login
    linux如何开机以命令行形式启动?
  • 原文地址:https://www.cnblogs.com/cs_net/p/1831421.html
Copyright © 2020-2023  润新知