但根据 java 的一般联系,它们应该返回相同的值。
Java 的equals-hashCode
合约要求如果两个对象由 相等Object.equals
,它们必须具有来自 的相同哈希码Object.hashCode
。但是默认实现Object.equals
是引用相等,因此两个实例是相同的当且仅当它们是相同的实例。
因此,特别是,您的两个实例t1
实际上t2
并不相等,因为您没有覆盖Object.equals
. 它们不等于引用,因此不等于 per Object.equals
,因此hashCode
可能返回不同的值是可以接受的。事实上,合同明确规定了以下内容:
不要求如果两个对象根据该equals(java.lang.Object)
方法不相等,则对两个对象中的每一个调用该hashCode
方法必须产生不同的整数结果。
因此,我们在这里没有违反equals-hashCode
合同。
因此,对于您的对象,如果您希望不同的实例根据相等的逻辑定义相等,则需要覆盖Object.equals
:
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
if (this == obj) {
return true;
}
if (!(obj instanceof Test)) {
return false;
}
Test other = (Test)obj;
return this.i == other.i && this.j == other.j;
}
并且equals-hashCode
合同要求你也覆盖,Object.hashCode
否则你会遇到一些讨厌的错误:
@Override
public int hashCode() {
int hash = 17;
hash = 31 * hash + this.i;
hash = 31 * hash + this.j;
return hash;
}
合同是怎么说的:
如果根据方法两个对象相等equals(Object)
,则对两个对象中的每一个调用该hashCode
方法必须产生相同的整数结果。
Let's see if we have satisfied this requirement here. If x
and y
are instances of Test
and satisfy x.equals(y)
is true
, we have that x.i == y.i
and x.j == y.j
. Then, clearly, if we invoke x.hashCode()
and y.hashCode()
we have the invariant that at each line of execution in Test.hashCode
we will have hash
holding the same value. Clearly this is true on the first line since hash
will be 17
in both cases. It will hold on the second line since this.i
will return the same value whether this == x
or this == y
because x.i
equals y.i
. Finally, on the penultimate line, we will still have hash
being equal across both invocations because x.j
equals y.j
is true as well.
Note that there is one last piece of the contract that we haven't discussed yet. This is the requirement that hashCode
return a consistent value during a single execution of a Java application:
Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode
method must consistently return the same integer, provided no information used in equals comparisons on the object is modified.
这样做的必要性是显而易见的。如果您hashCode
在同一应用程序的单次执行期间更改返回值,您可能会在hashCode
用于跟踪对象的类似哈希表的数据结构中丢失对象。尤其是,这就是为什么在类似哈希表的数据结构中改变作为键的对象是纯粹的邪恶。不要这样做。我什至会争辩说它们应该是不可变的对象。
事实上,当我做同样的事情String
或Integer
他们返回相同的时候hashcode()
。
他们都覆盖了Object.equals
和Object.hashCode
。