我的equals / hashCode方法应该检查的不仅仅是对象ID吗?

时间:2011-08-20 15:16:29

标签: java equals hashcode

在我的应用程序中,我有以下形式的模型类:

class Book
{
    private int ID;
    private String title;

    //other code
}

现在我的问题是两部分:

  1. 以下是equals()方法的良好实现吗?

    public boolean equals(Object o)
    {
        if(o == null)
        {
            return false;
        }
    
        if(!(o instanceof Book))
        {
            return false;
        }
    
        Book other = (Book)o;
    
        if(o.getID() == ID)
        {
            return true;
        }
        return false;
    }
    

    我知道equals()的实现很大程度上取决于我的 应用业务逻辑。但是,如果两本书具有相同的ID 理想情况下,他们必须是同一本书。因此我很困惑 我是否应该检查其他值字段的相等性 [标题,价格等]。

  2. 这是hashCode()方法的一个很好的实现:

    public int hashCode()
    {
        return ID;
    }
    

    我的想法是,不同的书籍会有不同的ID,如果 两本书具有相同的身份证,他们是平等的。因此以上 实现将确保哈希码的良好分布 我申请的背景。

6 个答案:

答案 0 :(得分:4)

只想在之前的答案中添加一些内容。 equals的合同提到它必须是对称的。这意味着a.equals(b) iff b.equals(a)

这就是为什么instanceof通常不在equals中使用的原因(除非该类是最终的)。实际上,如果Book(例如ComicsBook)的某些子类覆盖equals来测试另一个对象也是ComicsBook的实例,那么您将处于某种情况其中Book实例等于ComicsBook实例,但ComicsBook实例不等于Book实例。

你应这样(除非班级是最终的或在其他一些罕见的情况下)而是比较两个对象的类别:

if (this.getClass() != o.getClass()) {
    return false;
}

BTW,这就是Eclipse在生成hashCodeequals方法时所做的事情。

答案 1 :(得分:3)

不要这样做:

if(o.getID() == ID)

IDInteger对象,而不是原始对象。使用Integer比较两个不同但相等的==对象将返回false

使用此:

if(o.getID().equals(ID))

您还需要检查ID是否为null

除此之外,你的逻辑很好 - 你坚持认为两个相等的对象必须具有相同的哈希码的契约,并且你已经做出了关于什么是平等意味着什么的决定的业务逻辑决策 - 只有你的决定可以做(没有一个正确答案)。

答案 2 :(得分:3)

如果您使用Hibernate,那么您必须考虑一些与Hibernate相关的问题。

Hibernate为延迟加载创建代理。

  • 始终使用getter访问其他对象的属性(您已经这样做了)
  • 即使在正常的应用程序中使用if (!this.getClass().equals(o.getClass())) { return false;}是正确的,它也会因休眠代理(以及所有其他代理)而失败。原因是如果两者中的一个是代理,那么类将永远不会等于。因此,测试if(!(o instanceof Book)){return false;}就是您所需要的。

如果你想以对称方式进行,而不是在这个类的帮助下查看org.hibernate.proxy.HibernateProxyHelper.getClassWithoutInitializingProxy(),你可以实现:

if (!HibernateProxyHelper.getClassWithoutInitializingProxy(this)
     .equals(HibernateProxyHelper.getClassWithoutInitializingProxy(o))) {
   return false;
}
  • 另一个问题可能是ID - 当您为id分配新对象但稍后在存储它们时,则可能会遇到麻烦。假设这种情况:您创建一个ID为0的新书,然后将Book放入HashSet(它将根据哈希码分配给哈希集中的桶),稍后您将Book存储在数据库中并设置id让我们说1.但这会改变哈希码,你将有问题再次找到集合中的实体。 - 如果这对您来说是个问题,很大程度上取决于您的应用程序,体系结构以及如何使用休眠。

答案 3 :(得分:1)

比较像

这样的两个整数并不是一个好主意
if(o.getID() == ID) ...

这是对身份的测试。你想要的是对平等的考验:

if(ID!=null && ID.equals(o.getID())) ...

答案 4 :(得分:1)

请注意:您的等于方法

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

    if(!(o instanceof Book))
    {
        return false;
    }

    Book other = (Book)o;

    if(other.getID() == ID)
    {
        return true;
    }
    return false;
}

可以(等效地)缩写为:

public boolean equals(Object o) {
    return (o instanceof Book) &&
       ((Book)o).getID == ID;
}

除此之外,如果您的ID对于不同的书籍都是不同的(对于相同的书籍也是如此),这是一个很好的实现。

(但请注意JB Nizet的评论:为了确保它保持对称,请equals(或全班)final。)

答案 5 :(得分:0)

取决于!

我认为如果您能处理以下条件,这种实施方式是可以的,

你新出了两本书,这两本书有相同的标题,实际上它们是同一本书,但是你 不要将它们保存到数据库中,所以这两本书还没有id,比较它们时等于会降低

相关问题