c# 关于相等判断

来源:互联网 发布:jquery mobileui 知乎 编辑:程序博客网 时间:2024/06/04 18:35
今天介绍一下关于相等的判断,这应该是个基础的东西,但是又有很多值得深入研究的东西,
基本概念的东西太多,这个大家可以去查资料,
http://book.csdn.net/bookfiles/295/10029512576.shtml
通过这一节就已经可以对这几种方法有大体了解,再次不做介绍,
我主要是用例子来说明一下问题:
首先说明一下string字符串,string它是一个引用类型的,只不过是它拥有了值类型的特征,
而通过书中的介绍
ReferenceEquals方法不能继承,它用来专门比较引用类型是否相等,所以它是比较引用的首选,有了它我们可以毫无顾虑的判断,并且简单,看例子:
using System;
using System.Collections.Generic;
using System.Text;

namespace fanxing
{
    
class Class4
    
{


    }


    
class Application2
    
{

        
static void Main(string[] args)
        
{
            Class4 aclass4 
= new Class4();
            Class4 bclass4 
= new Class4();

            
//bclass4=aclass4; 这里加了注释,去掉注释后比较的结果完全不一样
            if (Object.ReferenceEquals(aclass4, bclass4))
            
{

                Console.Write(aclass4.GetHashCode() 
+ "===" + bclass4.GetHashCode());
            }

            
else
            
{

                Console.Write(
"false");
            }


int a=5;
int b=5;

if (Object.ReferenceEquals(a, b)) //这里比较值类型,所以肯定是false毫无疑问,它不是用来比较值类型的
            {

                Console.Write(a.GetHashCode() 
+ "===" + b.GetHashCode());
            }

            
else
            
{

                Console.Write(
"false");
            }


            
char[] c1 = new char[] 'a''a''a' };
            
char[] c2 = new char[] 'a''a''a' };

            
string str1 = "aaa";
            String a 
= "12345";
            String b 
= "";
            String c 
= "12345";
            b 
= b + '1';
            b 
= b + '2';
            b 
= b + '3';
            b 
= b + '4';
            b 
= b + '5';
            
string str2 = new String(c1);
            
string str3 = str2;
            
string str4 = "aaa";

            
//int aaa = 5;
            
//int bbb = 5;


            
if (Object.ReferenceEquals(a, c))  //比较字符串,已经介绍过字符串是特殊的引用类型
            {

                Console.Write(str3.GetHashCode() 
+ "===" + str2.GetHashCode());
            }

            
else
            
{

                Console.Write(
"false");
            }


            Console.Read();
        }

    }

}

上面的例子再次可以证明既然它能比较出连个字符串是否相等,就证明字符串肯定是引用类型,
再者如果比较字符串str1与str2,答案是不相等,因为str2新建了一个对象(new),所以两者不存在引用关系,
肯定是false,而我们再次再介绍一下,看了源码我发现string类没有重写“+"这个运算符号,所以我们在利用字符串进行相加时,只是单纯意义上的字符连接,可能不会像java一样每加一次会创建新对象,于是当我们进行字符串a和b进行比较时,会发现仍然相等,所以说明两者出于同一个对象,大家还有疑问时我们对字符串进行直接复制,就会new对象呢?答案是不会,看了java对此的解释,通常字符串有一个STRING池.当我们进行字符串直接复制时,都会通过这个string池,如果在string池中找到已有的字符串,那么就指向同一个字符串地址,与我们new一个string类是完全不一样。
继续介绍
equal和==在自定义类型是ValueType的时候要改写

当自定义类型是ReferenceType的时候,如果想改变RefrenceType默认的用对象标志判
等的方式,可以改写equal

当自定义类型是RefrenceType的时候,最好不要改写operator==.
还有需要注意的是==比较对于非自定义的值类型就是比较值得大小,
而对于比较引用类型,就是比较是否出自由同一个对象,
对于自定义的值类型如struct可以自己来重写,
对于自定义的引用类型class最好不要用来重写,
并且重写了==就需要重写!=还要重写equal,如果重写了equal就需要重写GetHashCode方法,
因为两者要相等就必须该方法返回值要相等。
using System;
using System.Collections.Generic;
using System.Text;

namespace fanxing
{
    
class car
    
{
        
private int speed;
        
private int num;
        
public car(int speed,int num)
        
{
            
this.speed = speed;
            
this.num=num;
        }


     

      
        
/*public override bool Equals(object x)
        {
            if (!(x is car))
            {
                return false;
            }
            else
            {
                return this == x as car;
            }
        }
*/


  
public override bool Equals( object right )

  
{


    
if (right == null)

      
return false;

    
if (object.ReferenceEquals( this, right ))

      
return true;


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

      
return false;


    
return CompareFooMembers(

      
this, right as car  );

  }


        
public bool CompareFooMembers(car aaa,car bbb)
        
{
            
if (aaa.speed == bbb.speed)
            
{
                
return true;
            }

            
else 
            
{
                
return false;
            }

        }


        
public override int GetHashCode()
        
{
            
return speed;
        }



    }




   
    
class Application1
    
{

       
static void Main(string[] args)
         
{
             car acar 
=new car(500,5);
             car bcar 
= new car(500,9);
             
if (acar.Equals(bcar))
             
{
                 Console.Write(acar.GetHashCode() 
+ "----" + bcar.GetHashCode());
             }

             
else
             
{
                 Console.Write(
"false");
             }

  
             Console.Read();
         }

    }


 }

注意我上面的例子定义了两个重写equal,用第一个的话为false因为它调用了==比较,我们介绍过==比较对象时是要比较两个是否出于一个对象,显然不是。加上这句acar=bcar;结果就是相等了。
再看第二种方法,因为我们是自定义的类,所以我们根据我们的需求判断两个对象相等的条件,这里我们选择speed,只要两个对象speed相等我们就判断这两个对象是相等的。
具体实现看代码大家已经八九不离十了,而大家看了我重写的
GetHashCode(),里面返回speed,这点需要说明的是,我提过重写equal必须要重写该方法要返回一样的值,那这个值什么?这里我选择了speed,当然我这个写法太简单了,对于重写GetHashCode()的规则很多,但道理都是一样的那就是:相等的对象必须返回相同的GetHashCode(),这个时候你就可以定里面返回的东西啦。
对于equal在比较非自定义的值类型时与==相同,
对比较引用类型的时候也是判断是否出于同一个对象,
下面我们接着介绍string,
既然string是引用类型,那
using System;
using System.Collections.Generic;
using System.Text;

namespace fanxing
{
    
class Class4
    
{


    }


    
class Application2
    
{

        
static void Main(string[] args)
        
{

            
char[] c1 = new char[] 'a''a''a' };
            
char[] c2 = new char[] 'a''a''a' };

            
string str1 = "aaa";
            String a 
= "12345";
            String b 
= "";
            String c 
= "12345";
            b 
= b + '1';
            b 
= b + '2';
            b 
= b + '3';
            b 
= b + '4';
            b 
= b + '5';  
            
string str2 = new String(c1);
            
string str3 = str2;
            
string str4 = "aaa";

            
int aaa = 5;
            
int bbb = 5;


            
if (Object.ReferenceEquals(a,b))
            
{

                Console.Write(str3.GetHashCode()
+"==="+str2.GetHashCode());
            }

            
else
            
{
                
                Console.Write(
"false");
            }



            
if (str1 == str2)
            
{
                Console.Write(
"true");
            }

            
else
            
{
                Console.Write(
"false");
            }


            
if (aaa.Equals(bbb))
            
{
                Console.Write(
"true");
            }

            
else
            
{
                Console.Write(
"false");
            }

            
            Console.Read();
        }

    }

}


命名str1和str2不是同一个引用(前面已经介绍),但为什么后面的比较确相等呢?
我们看源代码可知道string它重写了==和equal这两个方法,我们不追究里面的实现,
但至少它里面的实现应该是和我们前面提到的speed比较相似,并没有比较对象的引用,
而是比较对象的值,再次介绍完了,这两天不停的在写,其实也是对自己以后看起来比较容易,主要是对自己方便,
写的乱了点,顺便总结一下,希望看到的朋友感觉有什么地方不对,可以指出。


补充
using System;
using System.Collections.Generic;
using System.Text;

namespace fanxing
{
    
class Application333
    
{
        
static void Main(string[] args)
        
{
            
string a = "aaa";
            String str1 
= "b";
            
string b = str1 + "cc";
            
string c = "d" + "ee";
            Console.Read();
        }

    }

}


.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  
// 代码大小       38 (0x26)
  .maxstack  2
  .locals init ([
0string a,
           [
1string str1,
           [
2string b,
           [
3string c)
  IL_0000:  nop
  IL_0001:  ldstr      
"aaa"
  IL_0006:  stloc.
0
  IL_0007:  ldstr      
"b"
  IL_000c:  stloc.
1
  IL_000d:  ldloc.
1
  IL_000e:  ldstr      
"cc"
  IL_0013:  call       
string [mscorlib]System.String::Concat(string,
                                                              
string)
  IL_0018:  stloc.
2
  IL_0019:  ldstr      
"dee"
  IL_001e:  stloc.
3
  IL_001f:  call       int32 [mscorlib]System.Console::Read()
  IL_0024:  pop
  IL_0025:  ret
}
 // end of method Application333::Main

通过编译我们可以看到具体的字符串相加“+”的编译过程,具体通过
调用静态方法System.String::Concat来实现,所以看下面的例子的结果也就明白了

using System;
using System.Collections.Generic;
using System.Text;

namespace fanxing
{


    
class Application333
    
{
        
static void Main(string[] args)
        
{
            
string a = "aaa";
            String str1 
= "a";
            
string b = str1 + "aa";//动态生成的字符串,所以不放入散列中,ReferenceEquals比较为false
            string c = "a" + "aa";//由于都是字符串常量所以会在散列表中查找相应的字符串,找到即位true
            string d = string.Intern(b);//利用intern可以将动态生成的字符串放入散列当中,ReferenceEquals为true


            
if (Object.ReferenceEquals(a,d))
            
{
                Console.Write(
"true");
            }

            
else
            
{
                
                Console.Write(
"false");
            }


            
if (a == b)
            
{
                Console.Write(
"aa");
            }

            
else
            
{
                Console.Write(
"bb");
            }

           
            Console.Read();
        }

    }

}


原创粉丝点击