【问题标题】:Did I override equals and hashcode correctly?我是否正确覆盖了equals和hashcode?
【发布时间】:2013-06-02 22:01:15
【问题描述】:

在我最近的问题中,我被告知我需要覆盖我的 equalshashcode 方法(除其他外)。所以我花了一些时间阅读了几篇文章并试图提出一个正确的实现。

以下是我阅读的一些文章:

所有文章都很好。由于这是我第一次尝试这样做,我只是想确保我没有犯一些简单(或愚蠢)的错误。

我将使用name 来指示我的Person 对象是否等同于另一个Person 对象。原因是所有其他变量都可以变化,但名称始终是唯一的。

已更新以反映建议的更改

public class Person {

    private String name;
    private int p_number;
    private String address;
    //other variables

    public Person(String a_name) {
        name = a_name;
    }

    public String getName() {
        return name;
    }

    //other getters and setters

    @Override
    public boolean equals(Object o) {
        if(o == null) 
            return false;

        if(o == this) 
            return true;

        if(!(o instanceof Person)) 
            return false;

        Person p = (Person) o;
        return name.equals(p.name));

    }

    @Override
    public int hashCode() {
        return name.hashCode();
    }
}

我的问题如下:

  1. 我是否正确实施了这些方法?
  2. 由于name 是唯一决定唯一性的变量,我是否需要检查hashcode 中的任何其他变量?
  3. 我之前在 StackOverflow 上读到 31 被选为一个好的素数,但现在选择更大的素数更好吗?有人可以确认或否认这一说法吗? (索赔是在上面的第三个链接中提出的)

如果我没有正确实施这些方法,我该如何更改/改进它们?

【问题讨论】:

  • 像 Eclipse 这样的 IDE 将为您生成 equals()hashCode() 的良好实现。
  • @GriffeyDog 在我的最后一个问题中,一些帮助 SO'ers 也告诉了我这一点。但是,他们建议我不要生成任何我不理解的东西。
  • @WilliamShatner 这是他们的极好建议!
  • @fge 确实如此!这就是为什么我开始阅读它的原因。我希望能更好地理解这两种方法,因为我的项目很可能会广泛使用它。

标签: java overriding equals hashcode


【解决方案1】:

equals():

if(name.equals(p.getName()))
    return true;

缺少false,您可以:

// Both are Person instances, no need to use the accessor here
return name.equals(p.name);

至于hashCode(),就return name.hashCode()

另外,name 可以为空吗?你的方法似乎没有考虑到这一点。 (编辑:答案:否)

关于你的问题:

由于 name 是唯一决定唯一性的变量,我是否需要检查哈希码中的任何其他变量?

不,当然不是!如果您的姓名相同但年龄不同,这将导致相同对象的哈希码不同,这违反了Object 合约!

我在 StackOverflow 上读到 31 之前被选为一个好的素数,但现在选择更大的素数更好吗?有人可以确认或否认这一说法吗? (索赔是在上面的第三个链接中提出的)

这个,不知道...

为了更完整地了解.equals()/.hashCode() 合约,我将提到来自 Guava 的实用程序类:Equivalence。对于给定的这个抽象类的实现 类可以允许您创建Sets,因此Maps,将这些对象作为成员(键),就好像它们对这两个函数有一个不同的实现:

Equivalence<MyClass> eq = ....;

Set<Equivalence.Wrapper<MyClass>> set = ...;

set.add(eq.wrap(myClassInstance));

这实际上在某些情况下非常很有用...

【讨论】:

  • 好点,不,名称不能为空。感谢你能这么快回复!我会做这些修复
  • 注意.equals()的编辑:不需要使用访问器访问nameo
  • 另一件事:Person 可以扩展吗?
  • 谢谢,我注意到了你(以及 greedybuddha)的变化,我会在编辑课程时复习它们。 Person暂时不会延期。不过我也没有计划在未来扩展它。
  • 很遗憾你也有 setter,否则我建议也将实例变量设为 final。或者,也许您可​​以使用构建器来构建 Person 对象,这将允许该类是不可变的,这是一个不错的优势。
【解决方案2】:

您的equals 在所有情况下都需要返回一个值,只需将结尾部分更改为返回name.equals

@Override
public boolean equals(Object o) {
    ...
    return name.equals(o.getName());
}

此外,您的哈希码实际上是有害的,它所做的只是使用name.hashCode(),然后将其乘以 31,最好直接使用名称中的默认 Java 字符串哈希码。

@Override
public int hashCode() {
    return name.hashCode();
}

【讨论】:

  • 也感谢您的快速回复!很高兴看到你们俩都发表了相同的声明。我很高兴我没有偏离轨道太远。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-04
  • 1970-01-01
  • 2020-08-26
  • 2017-02-05
  • 2018-07-13
  • 1970-01-01
相关资源
最近更新 更多