根据equals和hashCode合约规则,下面的代码有什么问题吗?
class Test {
@Override
public int hashCode() {
int hash = 0;
//Calculate hash
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (this == obj)
return true;
if (getClass() != obj.getClass())
return false;
Test other = (Test) obj;
if(this.hashCode() == other.hashCode()) {
return true;
} else {
return false;
}
}
}
答案 0 :(得分:2)
根据hashcode / equals合同,没有任何错误。
但这并不一定能使代码正确。这完全取决于类的必需的等式语义。
例如,如果Test
对象可能需要超过2 ^ 32个不同的状态,那么这种方法可能无法工作...因为只有2 ^ 32个不同的值可以由hashCode()
方法返回。即使在sub 2 ^ 32的情况下,你依赖于类的完美散列函数的存在。找到/写一个函数永远不会实用。
另一点需要注意的是,您的方法通常不如以正常方式实现equals效率低。为什么?比较这个例子:
class Test {
private boolean field1;
private boolean field2;
@Override
public int hashCode() {
return (field1 ? 0 : 1) * 2 + (field2 ? 0 : 1);
}
@Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (this == obj)
return true;
if (getClass() != obj.getClass())
return false;
Test other = (Test) obj;
// version 1
if(this.hashCode() == other.hashCode()) {
return true;
} else {
return false;
}
// version 2
if (this.field1 == other.field1 && this.field2 == other.field2) {
return true;
} else {
return false;
}
}
}
现在比较"版本1"和"版本2"片段:
现在JIT编译器可能会显着优化,但在这种情况下,哈希码的计算可能会超过任何节省量。即使您缓存了哈希码(例如String
),您也需要条件为"恰到好处"基于哈希码的方法更好。
答案 1 :(得分:1)
假设你有hashCode
的具体实现,而不是"计算哈希"你的代码是正确的,甚至对某些情况也有意义。
例如,如果Test
基本上是Boolean
,即它只能有两个值。然后,如果您将hashCode
定义为:
public int hashCode() {
return value ? 1 : 0;
}
您的equals方法将完全正常运行。
另一个类似示例,如果您的Test
类是Integer
值对象。如果您将value
作为hash
返回,则等号将起作用并且在逻辑上是正确的。
基本规则是,只要您可以定义hashCode
以便它涵盖您班级的所有可能值,那么您就是好的。否则,equals
实现只是没有意义,因为它可以为某些逻辑上不同的对象返回true
。
P.S。对于那些说这个实现违反equals-hashcode合同的人。你完全错了。由于此实施的equals
与hashCode
同等作用,因此无法按照定义违反合同。
答案 2 :(得分:0)
这是不正确的,因为the hashCode
method不需要为对象的所有可能状态返回不同的int
。
如果两个对象根据equals(java.lang.Object)方法不相等,则不需要在两个对象中的每一个上调用hashCode方法必须生成不同的整数结果。但是,程序员应该知道为不等对象生成不同的整数结果可能会提高哈希表的性能。
理论上,两个对象可能彼此不相等,但它们返回相同的哈希码。
对null
,相同参考和不同类的测试似乎是正确的。
但是,您不必依赖哈希码来确定相等性,而是必须根据对象自己的字段和自己的相等标准进行自己的比较。
答案 3 :(得分:0)
两点。首先,不要从int hash = 0;
开始更好地从正值开始,比如说:int hash = 17;
这样可以避免将初始0乘以某些输入的危险,从而在最终输出中失去输入的影响哈希值。
其次,您对null
的明确测试是不必要的。尝试使用:
if (!(obj instanceOf MyType)) {
return false;
} else {
MyType myty = (MyType)obj;
...
}
如果instanceOf
为空或不属于false
,则obj
运算符将返回MyType
。