Equals,==,ReferenceEquals区别

比较值类型的相等性

代表:int

  1. ReferenceEquals():比较两个对象的引用,即地址。
  2. Equals():比较两个对象的内容。
  3. 比较运算符(==):比较两个对象的内容。

特例:struct无比较运算符(==)。

Code:

       
        static void Main(string[] args)
        {
            int int_a = 3;
            int int_b = 3;
            Console.WriteLine("值类型测试");
            Console.WriteLine("int_a.Equals(int_b):" + int_a.Equals(int_b));
            Console.WriteLine("int_a==int_b:" + (int_a == int_b));
            Console.WriteLine("object.ReferenceEquals(int_a, int_b):" + object.ReferenceEquals(int_a, int_b));
            Console.WriteLine("");

            TestStruct stru1 = new TestStruct();
            TestStruct stru2 = new TestStruct();
            Console.WriteLine("Struct 测试");
            Console.WriteLine("stru1.Equals(stru2):" + stru1.Equals(stru2));
            Console.WriteLine("stru1==stru2:compile error!");
            Console.WriteLine("object.ReferenceEquals(stru1, stru2):" + object.ReferenceEquals(stru1, stru2));
            Console.WriteLine("");
            }
       
       struct TestStruct
       {
           int one;
           int two;
           public TestStruct(int one, int two)
          {
             this.one = one;
             this.two = two;
          }
       }
运行结果:


比较引用类型的相等性

代表:Class

  1. ReferenceEquals():静态方法,比较两个引用是为内存中的相同地址,然作为静态方法,它不能被重写。
    public static bool ReferenceEquals(object objA, object objB);

  2. 虚拟的Equals():比较两个引用的地址,但可被重写为按照值来比较两个对象,重写的代码不会抛异常。重写Equals方法时需要重写hashcode,否则hashcode可能无法保持唯一性。

    public virtual bool Equals(object obj);

  3. 静态的Equals():比较两个引用的地址,其区别为静态的带两个参数,并对它们进行相等性比较。
    public static bool Equals(object objA, object objB);

  4. 比较运算符(==):比较两个对象的引用,会根据需要自动转换类型,也可被重载,但必须成对重载,即重载了“==”,就必须重载“!=”。

Code:

    
    public class TestClass
    {
        int one = 1;
        int two = 2;
    }

        
        static void Main(string[] args)
        {
            TestClass C1 = new TestClass();
            TestClass C2 = new TestClass();
            Console.WriteLine("Normal Class 测试");
            Console.WriteLine("C1.Equals(C2):" + C1.Equals(C2));
            Console.WriteLine("C1==C2:" + (C1 == C2));
            Console.WriteLine("object.ReferenceEquals(C1, C2):" + object.ReferenceEquals(C1, C2));
            Console.WriteLine("");

            String str_a = "abc";
            String str_b = "abc";
            Console.WriteLine("Nomral string 测试");
            Console.WriteLine("str_a.Equals(str_b):" + str_a.Equals(str_b));
            Console.WriteLine("str_a==str_b:" + (str_a == str_b));
            Console.WriteLine("object.ReferenceEquals(str_a, str_b):" + object.ReferenceEquals(str_a, str_b));
            Console.WriteLine("");

            String str1 = new string(new char[] { 'a', 'b', 'c' });
            String str2 = new string(new char[] { 'a', 'b', 'c' });
            Console.WriteLine("Special string 测试");
            Console.WriteLine("str1.Equals(str2):" + str1.Equals(str2));
            Console.WriteLine("str1==str2:" + (str1 == str2));
            Console.WriteLine("object.ReferenceEquals(str1, str2):" + object.ReferenceEquals(str1, str2));
            Console.WriteLine("");
        }
运行结果:


重写Equals,==:

主函数代码如上,类代码如下:

 
    public class TestClass
    {
        int one = 1;
        int two = 2;

        public override bool Equals(object obj)
        {
            if (obj == null)
            {
                return false;
            }
            TestClass C1 = obj as TestClass;
            //if (C1 == null)
            //{
            //    return false;
            //}
            return (one == C1.one) && (two == C1.two);
        }

        public static bool operator ==(TestClass C1, TestClass C2)
        {
            if (C1.one == C2.one && C1.two == C2.two)
                return true;
            else
                return false;
        }

        public static bool operator !=(TestClass C1, TestClass C2)
        {
            return !(C1 == C2);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode() + 10;
        }
    }
运行结果:


以上代码有风险,因为重载了“==”,所以在执行以下图片代码会出错。注意重载有风险,所以在重载时需要谨慎。

            //if (C1 == null)
            //{
            //    return false;
            //}


特例:两种类型的String

对应string类型,由以上代码及运行结果可知,直接给string赋值,若两个string的内容相同,则指向同一内存地址,而其他的引用类型(包括char数组赋值的string类型)却不是,原因在于直接赋值的string类型经过了享元模式的处理,即当多个string对象包含相同内容,则内存只创建一个string对象来对应不同的对象引用

这也于string类型变量的内存开辟有关,因为其一旦被创造就不可改变(包括长度和其中的任何字符都不可改动),所以可以对其进行享元模式处理,而不必担心会出其他的问题。

拓展:

如下图代码,str_a看起来像是在之前开辟内存的对象上多加了一些内容,而实际是,它将之前的内容复制一份,又重新创建了一个新的同名的对象,并开辟了一块新的内存来存储这个新str_a的内容(之前同名变量的内容和新的内容“abc”),而之前的str_a对象内存将会被GC回收。


str_a += "abc";
StringBuilder是对于字符串和字符执行动态操作的类,在StringBuilder内部有一个足够长的字符数组用于存放字符串对象,当字符串长度没有超过字符数组的长度时,所有的操作均是针对于同一个字符数组,当长度超过时,才会创建一个更长的数组,把原先的数据复制到新数组中。这也是在对字符串进行频繁的修改时,相对于string对象系统开销会小很多的原因。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值