本文正在参加「Java主题月 - Java Debug笔记活动」,详情查看活动链接
在Java中重写equals和hashCode时应考虑哪些问题?
什么问题/陷阱,必须重写时,必须考虑equals和hashCode?
高分回答:
理论(对于语言律师和数学倾向较高的人):
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一定相等
真心感谢帅逼靓女们能看到这里,如果这个文章写得还不错,觉得有点东西的话
求点赞👍 求关注❤️ 求分享👥 对8块腹肌的我来说真的 非常有用!!!
如果本篇博客有任何错误,请批评指教,不胜感激 !❤️❤️❤️❤️