实现equals()和hashCode()

本文探讨了在Java中为了在Set中正确使用持久类实例,重载equals()和hashCode()方法的重要性。文章解释了为什么简单地基于标识符值进行比较不可行,并提出了使用业务键值相等的概念来实现这些方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如果你有如下需求,你必须重载 equals()hashCode()方法:

  • 想把持久类的实例放入Set中(当表示多值关联时,推荐这么做)

  • 想重用脱管实例

Hibernate保证,持久化标识(数据库的行)和仅在特定会话范围内的Java标识是等值的。因此,一旦 我们混合了从不同会话中获取的实例,如果我们希望Set有明确的语义,我们必 须实现equals()hashCode()

实现equals()/hashCode()最显而易见的方法是比较两个对象 标识符的值。如果值相同,则两个对象对应于数据库的同一行,因此它们是相等的(如果都被添加到Set,则在Set中只有一个元素)。不幸的是,对生成的标识不能 使用这种方法。Hibernate仅对那些持久化对象赋标识值,一个新创建的实例将不会有任何标识值。此外, 如果一个实例没有被保存(unsaved),并且在一个Set中,保存它将会给这个对象 赋一个标识值。如果equals()hashCode()是基于标识值 实现的,则其哈希码将会改变,违反Set的契约。建议去Hibernate的站点看关于这个 问题的全部讨论。注意,这不是一个Hibernate问题,而是一般的Java对象标识和相等的语义问题。

我们建议使用业务键值相等(Business key equality)来实现equals()hashCode()。业务键值相等的意思是,equals()方法 仅仅比较来自业务键的属性,一个业务键将标识在真实世界里(一个天生的候选键) 的实例。

public class Cat {

    ...
    public boolean equals(Object other) {
        if (this == other) return true;
        if ( !(other instanceof Cat) ) return false;

        final Cat cat = (Cat) other;

        if ( !cat.getLitterId().equals( getLitterId() ) ) return false;
        if ( !cat.getMother().equals( getMother() ) ) return false;

        return true;
    }

    public int hashCode() {
        int result;
        result = getMother().hashCode();
        result = 29 * result + getLitterId();
        return result;
    }

}

 

注意,业务键不必是象数据库的主键那样是固定不变的。 对业务键而言,不可变或唯一的属性是好的候选。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值