重写equals和hashCode时必须考虑哪些问题/陷阱?
当前回答
理论(适用于语言律师和数学爱好者):
Equals () (javadoc)必须定义等价关系(它必须是自反的、对称的和可传递的)。此外,它必须是一致的(如果对象没有被修改,那么它必须一直返回相同的值)。此外,o.equals(null)必须总是返回false。
hashCode() (javadoc)也必须是一致的(如果对象没有按照equals()进行修改,它必须一直返回相同的值)。
这两种方法的关系是:
当a. = (b)时,则a.hashCode()必须与b. hashcode()相同。
在实践中:
如果你覆盖了一个,那么你也应该覆盖另一个。
使用用于计算equals()的相同字段集来计算hashCode()。
使用Apache Commons Lang库中的优秀辅助类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();
}
}
还记得:
当使用基于哈希的集合或映射(如HashSet、LinkedHashSet、HashMap、Hashtable或WeakHashMap)时,确保你放入集合中的关键对象的hashCode()在对象在集合中时永远不会改变。确保这一点的防弹方法是使您的密钥不可变,这还有其他好处。
其他回答
仍然令人惊讶的是,没有人推荐番石榴库。
//Sample taken from a current working project of mine just to illustrate the idea
@Override
public int hashCode(){
return Objects.hashCode(this.getDate(), this.datePattern);
}
@Override
public boolean equals(Object obj){
if ( ! obj instanceof DateAndPattern ) {
return false;
}
return Objects.equal(((DateAndPattern)obj).getDate(), this.getDate())
&& Objects.equal(((DateAndPattern)obj).getDate(), this.getDatePattern());
}
理论(适用于语言律师和数学爱好者):
Equals () (javadoc)必须定义等价关系(它必须是自反的、对称的和可传递的)。此外,它必须是一致的(如果对象没有被修改,那么它必须一直返回相同的值)。此外,o.equals(null)必须总是返回false。
hashCode() (javadoc)也必须是一致的(如果对象没有按照equals()进行修改,它必须一直返回相同的值)。
这两种方法的关系是:
当a. = (b)时,则a.hashCode()必须与b. hashcode()相同。
在实践中:
如果你覆盖了一个,那么你也应该覆盖另一个。
使用用于计算equals()的相同字段集来计算hashCode()。
使用Apache Commons Lang库中的优秀辅助类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();
}
}
还记得:
当使用基于哈希的集合或映射(如HashSet、LinkedHashSet、HashMap、Hashtable或WeakHashMap)时,确保你放入集合中的关键对象的hashCode()在对象在集合中时永远不会改变。确保这一点的防弹方法是使您的密钥不可变,这还有其他好处。
逻辑上我们有:
a.getClass().equals(b.getClass()) && a.equals(b) ⇒ a.hashCode() == b.hashCode()
但反之亦然!
我发现的一个问题是两个对象包含彼此的引用(一个例子是父/子关系,在父对象上有一个方便的方法来获取所有的子对象)。 例如,在执行Hibernate映射时,这类事情相当常见。
如果在hashCode或equals测试中包含关系的两端,则有可能进入以StackOverflowException结束的递归循环。 最简单的解决方案是在方法中不包括getChildren集合。
对于平等的人,可以看看Angelika Langer的《平等的秘密》。我非常喜欢它。她还提供了关于Java泛型的常见问题解答。在这里查看她的其他文章(向下滚动到“核心Java”),在那里她还继续介绍了第2部分和“混合类型比较”。祝你阅读愉快!
推荐文章
- 检查bash变量是否等于0
- 如何分割逗号分隔的字符串?
- Java字符串—查看字符串是否只包含数字而不包含字母
- Mockito.any()传递带有泛型的接口
- 在IntelliJ 10.5中运行测试时,出现“NoSuchMethodError: org.hamcrest. matcher . descripbemismatch”
- 使用String.split()和多个分隔符
- Java数组有最大大小吗?
- 在Android中将字符串转换为Uri
- 从JSON生成Java类?
- 为什么java.util.Set没有get(int index)?
- Swing和AWT的区别是什么?
- 为什么Java流是一次性的?
- 四舍五入BigDecimal *总是*有两位小数点后
- 设计模式:工厂vs工厂方法vs抽象工厂
- Java:检查enum是否包含给定的字符串?