zoukankan      html  css  js  c++  java
  • C#:Equals, ReferenceEquals与==的区别

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

    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上的方法
        }
    }


    引用类型的比较:

     1 using System;
     2 
     3 namespace ConsoleApplication14
     4 {
     5     class Program
     6     {
     7         static void Main(string[] args)
     8         {
     9             ReferneceClass c1 = new ReferneceClass();
    10             c1.X = 1;
    11             c1.Y = "OK";
    12 
    13             ReferneceClass c2 = new ReferneceClass();
    14             c2.X = 1;
    15             c2.Y = "OK";
    16 
    17             ReferneceClass c3 = new ReferneceClass();
    18             c3.X = 1;
    19             c3.Y = "OK!";
    20 
    21             ReferneceClass c4 = new ReferneceClass();
    22             c4.X = 2;
    23             c4.Y = "OK";
    24 
    25             ReferneceClass c5 = new ReferneceClass();
    26             c5 = c1;
    27             c5.X = 2;
    28 
    29             ReferneceClass c6 = c1;
    30 
    31             Console.WriteLine(ReferenceEquals(c1, c2).ToString()); // False
    32             Console.WriteLine(ReferenceEquals(c1, c3).ToString()); // False
    33             Console.WriteLine(ReferenceEquals(c1, c4).ToString()); // False
    34             Console.WriteLine(ReferenceEquals(c1, c5).ToString()); // True
    35             Console.WriteLine(ReferenceEquals(c1, c6).ToString()); // True
    36             Console.WriteLine();
    37             Console.WriteLine(Equals(c1, c2).ToString()); // False
    38             Console.WriteLine(Equals(c1, c3).ToString()); // False
    39             Console.WriteLine(Equals(c1, c4).ToString()); // False
    40             Console.WriteLine(Equals(c1, c5).ToString()); // True
    41             Console.WriteLine(Equals(c1, c6).ToString()); // True
    42             Console.WriteLine();
    43             Console.WriteLine(c1.Equals(c2).ToString()); // False
    44             Console.WriteLine(c1.Equals(c3).ToString()); // False
    45             Console.WriteLine(c1.Equals(c4).ToString()); // False
    46             Console.WriteLine(c1.Equals(c5).ToString()); // True
    47             Console.WriteLine(c1.Equals(c6).ToString()); // True
    48             Console.WriteLine();
    49             Console.WriteLine(c1 == c2); // False
    50             Console.WriteLine(c1 == c3); // False
    51             Console.WriteLine(c1 == c4); // False
    52             Console.WriteLine(c1 == c5); // True
    53             Console.WriteLine(c1 == c6); // True
    54             Console.WriteLine();
    55             Console.ReadLine();
    56         }
    57     }
    58 
    59     public class ReferneceClass
    60     {
    61         public int X
    62         {
    63             get;
    64             set;
    65         }
    66 
    67         public string Y
    68         {
    69             get;
    70             set;
    71         }
    72 
    73         public struct ValueStruce
    74         {
    75             public int x;
    76             public string y;
    77         }
    78     }
    79 }

    c1,c2,c3,c4为不同的实例,c1,c5,c6是同一个引用

     1 using System;
     2 
     3 namespace ConsoleApplication14
     4 {
     5     class Program
     6     {
     7         static void Main(string[] args)
     8         {
     9             ValueStruce c1 = new ValueStruce();
    10             c1.x = 1;
    11             c1.y = "OK";
    12 
    13             ValueStruce c2 = new ValueStruce();
    14             c2.x = 1;
    15             c2.y = "OK";
    16 
    17             ValueStruce c3 = new ValueStruce();
    18             c3.x = 1;
    19             c3.y = "OK!";
    20 
    21             ValueStruce c4 = new ValueStruce();
    22             c4.x = 2;
    23             c4.y = "OK";
    24 
    25             ValueStruce c5 = new ValueStruce();
    26             c5 = c1;
    27             c5.x = 2;
    28 
    29             ValueStruce c6 = c1;
    30 
    31             Console.WriteLine(ReferenceEquals(c1, c2).ToString()); // False
    32             Console.WriteLine(ReferenceEquals(c1, c3).ToString()); // False
    33             Console.WriteLine(ReferenceEquals(c1, c4).ToString()); // False
    34             Console.WriteLine(ReferenceEquals(c1, c5).ToString()); // False
    35             Console.WriteLine(ReferenceEquals(c1, c6).ToString()); // False
    36             Console.WriteLine();
    37             Console.WriteLine(Equals(c1, c2).ToString()); // True
    38             Console.WriteLine(Equals(c1, c3).ToString()); // False
    39             Console.WriteLine(Equals(c1, c4).ToString()); // False
    40             Console.WriteLine(Equals(c1, c5).ToString()); // False
    41             Console.WriteLine(Equals(c1, c6).ToString()); // True
    42             Console.WriteLine();
    43             Console.WriteLine(c1.Equals(c2).ToString()); // True
    44             Console.WriteLine(c1.Equals(c3).ToString()); // False
    45             Console.WriteLine(c1.Equals(c4).ToString()); // False
    46             Console.WriteLine(c1.Equals(c5).ToString()); // False
    47             Console.WriteLine(c1.Equals(c6).ToString()); // True
    48             
    49             Console.ReadLine();
    50         }
    51     }
    52 
    53     public class ReferneceClass
    54     {
    55         public int X
    56         {
    57             get;
    58             set;
    59         }
    60 
    61         public string Y
    62         {
    63             get;
    64             set;
    65         }
    66     }
    67 
    68     public struct ValueStruce
    69     {
    70         public int x;
    71         public string y;
    72     }
    73 }
    • 静态ReferenceEquals,从方法名也可以看出比较的是引用地址,在堆值类型进行比较的时候,始终为false,即使是ReferenceEquals(1,1),因为这里它这里把值先装箱再进行比较,所以两个引用地址是不一样的,但是ReferenceEquals(null,null)的值是True。
    • 静态方法Equals(object objA, object objB) 这个方法其实最终调用了虚拟Equals方法的不同重载。
    • 虚拟Equals方法,可在不同类中重载,比如String.Equals方法就是用于判断两个字符串的内容是否相等。一般来说,对于值类型,类型相同,并且数值相同(对于Struct的每个成员都必须相同),则Equals返回True,否则返回False。而对于引用类型,默认的行为与ReferenceEquals的行为相同,仅有两个对象指向同一个Reference的时候才返回True。静态Equals相比虚拟Equals方法有一个优点,就在于它不用考虑比较的对象是否为null。
    • ==运算符,对于内置的值类型,直接判断两个对象的值是否相等,并会根据需要对对象进行类型转换,对于用户定义的值类型,比如Struct,不可使用;对于引用类型,默认的行为与ReferenceEquals的行为相同,但是很多类对==进行了重载,比如String。
     1 using System;
     2 
     3 namespace ConsoleApplication12
     4 {
     5     class Program
     6     {
     7         static void Main(string[] args)
     8         {
     9             string a = new string(new char[] { 'h', 'e', 'l', 'l', 'o' });
    10             string b = new string(new char[] { 'h', 'e', 'l', 'l', 'o' });
    11             Console.WriteLine(a == b);
    12             Console.WriteLine(a.Equals(b));
    13 
    14             object g = a;
    15             object h = b;
    16             Console.WriteLine(g == h);
    17             Console.WriteLine(g.Equals(h));
    18 
    19             Person p1 = new Person("jia");
    20             Person p2 = new Person("jia");
    21             Console.WriteLine(p1 == p2);
    22             Console.WriteLine(p1.Equals(p2));
    23 
    24             Person p3 = new Person("jia");
    25             Person p4 = p3;
    26             Console.WriteLine(p3 == p4);
    27             Console.WriteLine(p3.Equals(p4));
    28 
    29             Console.ReadLine();
    30 
    31         }
    32     }
    33 
    34     class Person
    35     {
    36         private string name;
    37 
    38         public string Name
    39         {
    40             get
    41             {
    42                 return name;
    43             }
    44             set
    45             {
    46                 name = value;
    47             }
    48         }
    49 
    50         public Person(string name)
    51         {
    52             this.name = name;
    53         }
    54     }
    55 }

    运行结果:

  • 相关阅读:
    「BZOJ1061」 [Noi2008]志愿者招募
    [POJ 2891] Strange Way to Express Integers (扩展中国剩余定理)
    扩展中国剩余定理学习笔记
    扩展欧几里得算法+推论
    SPOJ16607 IE1
    [Luogu P4124] [CQOI2016]手机号码 (数位DP)
    [UOJ 275/BZOJ4737] 【清华集训2016】组合数问题 (LUCAS定理的运用+数位DP)
    一些很妙的网站
    [Luogu P3157][CQOI2011]动态逆序对 (树套树)
    [Luogu P3203] [HNOI2010]弹飞绵羊 (LCT维护链的长度)
  • 原文地址:https://www.cnblogs.com/LilianChen/p/2961243.html
Copyright © 2011-2022 走看看