在Java中重写equals和hashCode时应考虑哪些问题?推荐| Java Debug 笔记

116 阅读4分钟

本文正在参加「Java主题月 - Java Debug笔记活动」,详情查看活动链接

在Java中重写equals和hashCode时应考虑哪些问题?

什么问题/陷阱,必须重写时,必须考虑equals和hashCode?

高分回答:

很多的知识点,真的需要写出来才会掌握!!! \color{purple}很多的知识点,真的需要写出来才会掌握!!!{~}

理论(对于语言律师和数学倾向较高的人):

equals()(javadoc)必须定义一个等价关系(它必须是自反的,对称的和可传递的)。另外,它必须是一致的(如果未修改对象,则必须保持返回相同的值)。此外,o.equals(null)必须始终返回false。

hashCode()(javadoc)也必须是一致的(如果未根据修改对象equals(),则它必须保持返回相同的值)。

该关系的两种方法之间是:

无论何时a.equals(b),那么都a.hashCode()必须与相同b.hashCode()。

在实践中:

如果覆盖一个,则应覆盖另一个。

使用用于计算的相同字段集equals()进行计算hashCode()。

使用优秀的辅助类EqualsBuilder和HashCodeBuilder从阿帕奇共享郎库。一个例子:

public class Person {
    private String name;
    private int age;
    // ...

    @Override
    public int hashCode() {
        return new HashCodeBuilder(17, 31). // two randomly chosen prime numbers
            // if deriving: appendSuper(super.hashCode()).
            append(name).
            append(age).
            toHashCode();
    }

    @Override
    public boolean equals(Object obj) {
       if (!(obj instanceof Person))
            return false;
        if (obj == this)
            return true;

        Person rhs = (Person) obj;
        return new EqualsBuilder().
            // if deriving: appendSuper(super.equals(obj)).
            append(name, rhs.name).
            append(age, rhs.age).
            isEquals();
    }
}

还请记住:

当使用基于哈希的Collection或Map(例如HashSet,LinkedHashSet,HashMap,Hashtable或WeakHashMap)时,请确保当对象位于集合中时,放入集合中的键对象的hashCode()永远不会改变。确保这一点的防弹方法是使您的钥匙不可变,这还有其他好处。

高分回答:

如果您正在处理使用像Hibernate这样的使用对象关系映射器(ORM)持久化的类,则有一些值得注意的问题,如果您不认为这已经变得不合理地复杂的话!

延迟加载的对象是子类

如果您的对象是使用ORM持久保存的,那么在许多情况下,您将使用动态代理来避免从数据存储中加载对象太早。这些代理被实现为您自己类的子类。这意味着this.getClass() == o.getClass()将返回false。例如:

Person saved = new Person("John Doe");
Long key = dao.save(saved);
dao.flush();
Person retrieved = dao.retrieve(key);
saved.getClass().equals(retrieved.getClass()); // Will return false if Person is loaded lazy

如果您正在处理ORM,o instanceof Person则只有使用才能正确运行。

延迟加载的对象具有空字段

ORM通常使用吸气剂来强制加载延迟加载的对象。这意味着,person.name将是null,如果person是懒加载,即使person.getName()迫使装载并返回“李四”。以我的经验,这种现象在hashCode()和出现的频率更高equals()。

如果要处理ORM,请确保始终使用getter,并且切勿在hashCode()和中使用字段引用equals()。

保存对象将更改其状态

持久性对象通常使用id字段来保存对象的键。首次保存对象时,此字段将自动更新。请勿在中使用id字段hashCode()。但是您可以在中使用它equals()。

我经常使用的模式是

if (this.getId() == null) {
    return this == other;
}
else {
    return this.getId().equals(other.getId());
}

但是:你可以不包括getId()在hashCode()。如果这样做,则持久化对象时,对象将hashCode发生更改。如果对象位于中HashSet,您将“永远”不再找到它。

在我的Person示例中,我可能会使用getName()forhashCode和getId()plus getName()(仅用于偏执狂)equals()。如果存在“冲突”的风险是可以的hashCode(),但绝对不能equals()。

hashCode() 应该使用以下属性的不变子集 equals()

文章翻译自kgs4h5t57thfb6iyuz6dqtun5y-ac4c6men2g7xr2a-stackoverflow-com.translate.goog/questions/2…

作者建议:Ojbect类中有两个方法equals、hashCode,这两个方法都是用来比较两个对象是否相等的,如果两个对象相等(equal),那么必须拥有相同 的哈希码(hash code) hashcode相等,两个对象不一定相等 两个对象相等(根据内存地址hash的),hashcode一定相等

欢迎关注我的专栏StackOverFlow,我会筛选优质的问答,面试常考!!! \color{red}欢迎关注我的专栏StackOverFlow,我会筛选优质的问答,面试常考!!!{~}

有最新、优雅的实现方式,我也会在文末写出我对本问答的见解 \color{red}有最新、优雅的实现方式,我也会在文末写出我对本问答的见解{~}

真心感谢帅逼靓女们能看到这里,如果这个文章写得还不错,觉得有点东西的话

求点赞👍 求关注❤️ 求分享👥 对8块腹肌的我来说真的 非常有用!!!

如果本篇博客有任何错误,请批评指教,不胜感激 !❤️❤️❤️❤️