重写equals和hashCode时必须考虑哪些问题/陷阱?
当前回答
超类中有两个方法,如java.lang.Object。我们需要将它们重写为自定义对象。
public boolean equals(Object obj)
public int hashCode()
相等的对象只要相等就必须产生相同的哈希码,然而不相等的对象不需要产生不同的哈希码。
public class Test
{
private int num;
private String data;
public boolean equals(Object obj)
{
if(this == obj)
return true;
if((obj == null) || (obj.getClass() != this.getClass()))
return false;
// object must be Test at this point
Test test = (Test)obj;
return num == test.num &&
(data == test.data || (data != null && data.equals(test.data)));
}
public int hashCode()
{
int hash = 7;
hash = 31 * hash + num;
hash = 31 * hash + (null == data ? 0 : data.hashCode());
return hash;
}
// other methods
}
如果你想了解更多,请点击这个链接http://www.javaranch.com/journal/2002/10/equalhash.html
这是另一个例子, http://java67.blogspot.com/2013/04/example-of-overriding-equals-hashcode-compareTo-java-method.html
玩得开心!@ .@
其他回答
在检查成员是否相等之前,有几种方法可以检查类是否相等,我认为这两种方法在适当的情况下都是有用的。
使用instanceof操作符。 使用this.getClass () .equals (that.getClass())。
我在最终的等号实现中使用#1,或者在实现指定等号算法的接口时使用#1。util集合接口-检查with (obj instanceof Set)或任何你正在实现的接口的正确方法)。当等号可以被重写时,这通常是一个糟糕的选择,因为这会破坏对称性。
选项#2允许安全地扩展类,而不重写等号或破坏对称性。
如果你的类也是Comparable类,equals和compareTo方法也应该是一致的。下面是Comparable类中equals方法的模板:
final class MyClass implements Comparable<MyClass>
{
…
@Override
public boolean equals(Object obj)
{
/* If compareTo and equals aren't final, we should check with getClass instead. */
if (!(obj instanceof MyClass))
return false;
return compareTo((MyClass) obj) == 0;
}
}
逻辑上我们有:
a.getClass().equals(b.getClass()) && a.equals(b) ⇒ a.hashCode() == b.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());
}
我发现的一个问题是两个对象包含彼此的引用(一个例子是父/子关系,在父对象上有一个方便的方法来获取所有的子对象)。 例如,在执行Hibernate映射时,这类事情相当常见。
如果在hashCode或equals测试中包含关系的两端,则有可能进入以StackOverflowException结束的递归循环。 最简单的解决方案是在方法中不包括getChildren集合。
理论(适用于语言律师和数学爱好者):
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()在对象在集合中时永远不会改变。确保这一点的防弹方法是使您的密钥不可变,这还有其他好处。
推荐文章
- 在流中使用Java 8 foreach循环移动到下一项
- 访问限制:'Application'类型不是API(必需库rt.jar的限制)
- 用Java计算两个日期之间的天数
- 如何配置slf4j-simple
- 在Jar文件中运行类
- 带参数的可运行?
- 我如何得到一个字符串的前n个字符而不检查大小或出界?
- 我可以在Java中设置enum起始值吗?
- Java中的回调函数
- c#和Java中的泛型有什么不同?和模板在c++ ?
- 在Java中,流相对于循环的优势是什么?
- Jersey在未找到InjectionManagerFactory时停止工作
- 在Java流是peek真的只是调试?
- Recyclerview不调用onCreateViewHolder
- 将JSON字符串转换为HashMap