我读到,当重写equals()时,应该始终有when ()。
有人能给出一个实际的例子,说明为什么它可能是错误的,否则呢?即当覆盖等于()而不是hashCode()时可能出现的问题。
当我们重写等于()时,是否需要编写一个健壮的hasCode()函数?还是一个简单的实现就足够了?
例如,
下面这种糟糕的实现足以满足equals() & hashCode()之间的约定?
public int hashCode() {
return 91;
}
发布于 2012-12-10 16:06:11
equals()
和hashCode()
是在某些集合(如HashSet
和HashMap
)中联合使用的,因此您必须确保如果使用这些集合,则必须根据约定覆盖hashCode
。
如果您根本不覆盖hashCode
,那么HashSet
和HashMap
就会有问题。特别是,两个“相等”的对象可以放在不同的散列桶中,尽管它们应该是相等的。
如果您确实覆盖了hashCode
,但是操作很差,那么您就会出现性能问题。HashSet
和HashMap
的所有条目都将放在同一个桶中,您将失去O(1)的性能,取而代之的是O(n)。这是因为数据结构本质上变成了一个线性检查的链表。
至于破坏这些条件之外的程序,这是不可能的,但您永远不知道API (特别是第三方库中的API)何时将依赖于这个契约。对于没有实现任何一个对象的对象,契约都是被维护的,因此可以想象库可能在某个地方依赖于此而不使用散列桶。
在任何情况下,实现一个好的hashCode
都很容易,特别是在使用IDE的情况下。Eclipse和Netbeans都具有为您生成equals
和hashCode
的能力,可以遵循所有契约,包括equals
的逆规则(断言a.equals(b) == b.equals(a)
)。您所需要做的就是选择要包含的字段。
发布于 2012-12-10 16:07:40
equals
和hashcode
都是基于对象的单一性原则。如果equals
返回true
,则两个对象的哈希代码必须相同,否则基于哈希的结构和算法可能会有未定义的结果。
考虑基于哈希的结构,如HashMap
。将调用hashcode
作为获取密钥引用的基础,而不是equals
,这使得在大多数情况下不可能找到密钥。另外,hashcode
的一个糟糕的实现会产生冲突(同一个hashcode
的多个对象,哪一个是“正确的”对象?)这会影响性能。
IMHO,覆盖equals
或hashcode
(而不是覆盖两者)应该被认为是一种代码气味,或者至少是潜在的bug源。也就是说,除非您100%肯定它迟早不会影响您的代码(我们什么时候这么确定?)。
注意:有各种库可以通过equals
和hashcode
构建器来提供对此的支持,比如阿帕奇公域与HashcodeBuilder
和EqualsBuilder
。
发布于 2012-12-10 16:29:36
下面的代码说明了您可以通过不实现hashCode()来引入一个bug : Set.contains()将首先检查对象的hashCode(),然后检查.equals()。因此,如果不同时实现这两种功能,.contains()就不会以直观的方式运行:
public class ContainsProblem {
// define a class that implements equals, without implementing hashcode
class Car {
private String name;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Car)) return false;
Car car = (Car) o;
if (name != null ? !name.equals(car.name) : car.name != null) return false;
return true;
}
public String getName() {return name;}
public Car(String name) { this.name = name;}
}
public static void main(String[] args) {
ContainsProblem oc = new ContainsProblem();
ContainsProblem.Car ford = oc.new Car("ford");
ContainsProblem.Car chevy = oc.new Car("chevy");
ContainsProblem.Car anotherFord = oc.new Car("ford");
Set cars = Sets.newHashSet(ford,chevy);
// if the set of cars contains a ford, a ford is equal to another ford, shouldn't
// the set return the same thing for both fords? without hashCode(), it won't:
if (cars.contains(ford) && ford.equals(anotherFord) && !cars.contains(anotherFord)) {
System.out.println("oh noes, why don't we have a ford? isn't this a bug?");
}
}
}
https://stackoverflow.com/questions/13804547
复制相似问题