C#常考随笔3:对象比较obj1.Equals(obj2)== true时候,hashcode是否相同?
一般情况下是相同的,但在自定义类型中,重写了Equals方法,就可能不同。
Equals:
1. 首先,关于Equals方法:
Equals
方法最初定义在 Object
类中,所有的类都直接或间接地继承自 Object
类,因此所有对象都可以调用该方法。Object
类中的 Equals
方法默认比较的是对象的引用是否相等,即判断两个变量是否指向内存中的同一个对象实例。
示例代码:
using System;
class Program
{
static void Main()
{
object obj1 = new object();
object obj2 = obj1;
object obj3 = new object();
Console.WriteLine(obj1.Equals(obj2)); // 输出: True,因为 obj1 和 obj2 引用同一个对象
Console.WriteLine(obj1.Equals(obj3)); // 输出: False,因为 obj1 和 obj3 引用不同的对象
}
}
2. 重写 Equals
方法
许多类会重写 Equals
方法,以便根据对象的内容来判断它们是否相等,而不仅仅是比较引用。例如,string
类就重写了 Equals
方法,用于比较两个字符串的内容是否相同。
示例代码:
using System;
class Program
{
static void Main()
{
string str1 = "hello";
string str2 = "hello";
Console.WriteLine(str1.Equals(str2)); // 输出: True,因为 str1 和 str2 的内容相同
}
}
3. 自定义类重写 Equals
方法
当创建自定义类时,如果需要根据对象的属性来判断对象是否相等,就需要重写 Equals
方法。同时,为了遵循最佳实践,还应该重写 GetHashCode
方法,因为相等的对象应该具有相同的哈希码。
示例代码:
using System;
class Person
{
public string Name { get; set; }
public int Age { get; set; }
public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
return false;
Person other = (Person)obj;
return Name == other.Name && Age == other.Age;
}
public override int GetHashCode()
{
return HashCode.Combine(Name, Age);
}
}
class Program
{
static void Main()
{
Person person1 = new Person { Name = "Alice", Age = 25 };
Person person2 = new Person { Name = "Alice", Age = 25 };
Console.WriteLine(person1.Equals(person2)); // 输出: True,因为两个对象的属性值相同
}
}
什么时候hascode同,什么时候不同
以下是一个符合正常规则的示例:
using System;
class Program
{
static void Main()
{
string x = "hello";
string y = "hello";
bool areEqual = x.Equals(y);
int hashCodeX = x.GetHashCode();
int hashCodeY = y.GetHashCode();
Console.WriteLine($"Are equal: {areEqual}");
Console.WriteLine($"Hash code of x: {hashCodeX}");
Console.WriteLine($"Hash code of y: {hashCodeY}");
Console.WriteLine($"Hash codes are equal: {hashCodeX == hashCodeY}");
}
}
在上述代码中,x
和 y
是两个值相同的字符串对象,它们通过 Equals
方法比较返回 true
,并且它们的哈希码也是相同的。
特殊情况
如果在自定义类型中,手动重写了 Equals
方法和 GetHashCode
方法,并且没有遵循 “相等对象具有相同哈希码” 的原则,就可以让两个通过 Equals
方法比较相等的对象具有不同的哈希码。但这种做法是不推荐的,因为它会破坏很多基于哈希码的集合类的正常工作。
以下是一个错误示范的示例:
using System;
class MyClass
{
public int Value { get; set; }
public MyClass(int value)
{
Value = value;
}
public override bool Equals(object obj)
{
if (obj is MyClass other)
{
return this.Value == other.Value;
}
return false;
}
public override int GetHashCode()
{
// 故意返回不同的哈希码
return new Random().Next();
}
}
class Program
{
static void Main()
{
MyClass x = new MyClass(10);
MyClass y = new MyClass(10);
bool areEqual = x.Equals(y);
int hashCodeX = x.GetHashCode();
int hashCodeY = y.GetHashCode();
Console.WriteLine($"Are equal: {areEqual}");
Console.WriteLine($"Hash code of x: {hashCodeX}");
Console.WriteLine($"Hash code of y: {hashCodeY}");
Console.WriteLine($"Hash codes are equal: {hashCodeX == hashCodeY}");
}
}
在这个示例中,MyClass
类重写了 Equals
方法和 GetHashCode
方法,Equals
方法根据 Value
属性判断两个对象是否相等,但 GetHashCode
方法返回一个随机数,这就导致两个相等的对象可能具有不同的哈希码。需要修改:
public override int GetHashCode()
{
return HashCode.Combine(Value);
}