-4

如果我有引用类型对象,并且我创建了两个具有相同属性的对象,它们会有相同的哈希码吗?

样本类:

class Person
{
   int id;
   string name;

   public Person(int pid, string pname)
   {
      this.id = pid;
      this.name = pname;
   }
}

然后定义两个对象:

Person p1 = new Person(1,"xxx");
Perdon p2 = new Person(1,"xxx");

//p1.GetHashCode() = p2.GetHashCode() ??

编辑:我尝试了这段代码并得到了不同的结果,但是在字符串上测试东西给了我相同的结果
,我为什么要问

4

4 回答 4

1

如果 Person 是一个结构,那么哈希码将从成员值生成,并且您将得到相同的结果。但是,对于一个类,默认的哈希码实现将为每个对象提供一个唯一的哈希码,基于它们的内存引用。

因此,在这种情况下,如果您希望 p1 和 p2 具有相同的哈希码,则必须提供自己的实现。

于 2012-08-30T09:17:48.603 回答
1

您有责任GetHashCode自己实施。如果您不这样做,尽管它们应该具有相同的哈希码,但它们将不会具有相同的哈希码。

于 2012-08-30T09:18:08.140 回答
1

默认实现见这里:http: //msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx

GetHashCode 方法的默认实现不保证不同对象的唯一返回值。此外,.NET Framework 不保证 GetHashCode 方法的默认实现,它返回的值在不同版本的 .NET Framework 之间是相同的。因此,此方法的默认实现不得用作散列目的的唯一对象标识符。

但我认为你真正想知道的是哈希码是如何工作的。

假设您有以下课程:

public Person
{
    private string name;
    public Person(Name name)
    {
        this.name = name;
    }
}

现在,假设你想比较两个 Person 并检查他们是否有相同的名字,你是怎么做的?您覆盖在 Object 中实现的等号。(C# 中的所有类都隐式扩展 Object)像这样:

public Person
{
    private string name;
    public Person(Name name)
    {
        this.name = name;
    }

    public override bool Equals(Object obj)
    {
        if(obj == null)
            return false // not equal if obj is null

        Equals temp = obj as Equals; // temp set to null if obj can not be cast to equals
        if(p == null)
            return false

        // if code gets here, the code object passed is an instance of Equals.
        // Now we have to check if the strings match.
        bool isEqual = p.name == this.name; // set if the two names match
        return isEqual; // return if these two match
    }
}

所以现在,你可以检查两个人是否相等。例子:

Person p1 = new Person("Jack");
Person p2 = new Person("Jack");
Person p3 = new Person("Jill");
Object p4 = new Person("Jill");

p1.Equals(p2) // returns true
p1.Equals(p3) // returns false
p4.Equals(p1) // returns false
p4.Equals(p3) // returns true

现在,假设您有一个庞大的人员列表,例如一百万,并且您想知道"amy"此列表中是否存在被命名的人。你会怎么找到这个人?您是否会一一遍历所有名称并检查该 Person 是否等于 amy?但这会很慢,如果艾米是这个名单中的第 100 万人怎么办?我们如何提高性能?

输入哈希码。

假设您编写了一个简单的哈希码算法:哈希码是人名中每个字母的每个数字的总和。

public Person
{
    private string name;
    public Person(Name name)
    {
        this.name = name;
    }

    public  override bool Equals(Object obj)
    {
        if(obj == null)
            return false // not equal if obj is null

        Equals temp = obj as Equals; // temp set to null if obj can not be cast to equals
        if(p == null)
            return false

        // if code gets here, the code object passed is an instance of Equals.
        // Now we have to check if the strings match.
        bool isEqual = p.name == this.name; // set if the two names match
        return isEqual; // return if these two match
    }

    public override int GetHashCode()
    {
        int sum = 0;
        foreach(char c in this.name)
        {
            sum += c;
        }
        return sum;
    }
}

所以如果我们有amy她的哈希码1 + 13 + 25,那么38

现在,您有一个带有所谓“桶”的列表,而不是普通列表。你的哈希码决定了你去哪个桶。如果她进入 bucket ,amy则有一个 hascode 。3838

现在假设我们有另一个人,names may,她的名字中有相同的字母,所以她的哈希码也是38,她也进入桶38

现在,每当您想检查 amy 是否存在于此列表中时。我们首先检查她的哈希码,38现在我们在桶 38 中查找,并遍历桶中的所有对象,38我们检查桶中的任何对象是否38与 amy 匹配,如果为 true,则返回 true,如果为 false,则返回 false。因此,如果您有一百万人,那么您必须执行的检查列表以了解amy此列表中是否存在将大大减少。

所以基本上,如果你要使用哈希码,你必须遵守以下规则:

  • 如果你要使用哈希码,你必须重写和实现 equals。
  • 对于 Equals 返回 true 的两个对象,它们必须始终具有相同的哈希码
  • 不同的两个对象可能具有相同的哈希码,但不一定必须相同。

这基本上就是它的要点。

于 2012-08-30T10:26:34.043 回答
0

默认情况下它们不会(对于引用类型)。你可以试试这个看看。

如果您希望它们具有相同的哈希码,则必须相应地编写自己的 GetHashCode()。

于 2012-08-30T09:18:31.150 回答