我在这里写一个示例代码:
public class Test {
private int i;
private int j;
public Test() {
// TODO Auto-generated constructor stub
}
public Test(int i, int j)
{
this.i=i;
this.j=j;
}
}
现在我正在创建两个对象:
Test t1= new Test(4,5);
Test t2 = new Test(4,5);
但是当我打印t1.hashcode()和t2.hashcode()时,它们会给出不同的值。 但是根据java的一般联系,他们应该返回相同的值。 事实上,当我使用String或Integer做同样的事情时,他们返回相同的hashcode()。任何人都可以解释为什么hashcode对于t1和t2对象不同?
答案 0 :(得分:19)
但是根据java的一般联系,他们应该返回相同的值。
Java的equals-hashCode
合同要求如果两个对象相等Object.equals
,则它们必须具有Object.hashCode
中相同的哈希码。但Object.equals
的默认实现是引用相等,因此当且仅当它们是同一个实例时,两个实例是相同的。
因此,特别是,您的两个实例t1
和t2
实际上不相等,因为您没有覆盖Object.equals
。它们不等于引用,因此不等于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
方法必须产生相同的整数结果。
让我们看看我们是否满足了这个要求。如果x
和y
是Test
的实例并且x.equals(y)
满足true
,则我们会x.i == y.i
和x.j == y.j
。然后,显然,如果我们调用x.hashCode()
和y.hashCode()
,我们就会得到不变量,即在Test.hashCode
的每一行执行中,我们将hash
保持相同的值。显然,这是第一行,因为hash
在两种情况下都是17
。它将保留在第二行,因为this.i
将返回相同的值this == x
或this == y
,因为x.i
等于y.i
。最后,在倒数第二行,我们仍然会在两次调用中hash
相等,因为x.j
等于y.j
也是如此。
请注意,我们还没有讨论合同的最后一部分。这是hashCode
在单次执行Java应用程序期间返回一致值的要求:
每当在执行Java应用程序期间多次在同一对象上调用它时,
hashCode
方法必须始终返回相同的整数,前提是不修改对象上的equals比较中使用的信息。
这一点的必要性是显而易见的。如果在单次执行同一应用程序期间从hashCode
更改返回值,则可能会丢失使用hashCode
来跟踪对象的类哈希表数据结构中的对象。特别是,这就是为什么变异对象是哈希表类数据结构中的键是纯粹的邪恶;不要这样做。我甚至认为它们应该是不可改变的对象。
事实上,当我与
String
或Integer
做同样的事情时,他们会返回相同的hashcode()
。
他们都覆盖了Object.equals
和Object.hashCode
。
答案 1 :(得分:3)
您没有覆盖类中的equals
方法,因此将使用属于Object
类的默认方法。
对象类方法只是检查引用是否它们是指同一个对象。
Test t1 = new Test(4,5);
Test t2 = new Test(4,5);
是两个不同的对象,如果你不在这里覆盖equals
方法,当且仅当你做
Test t2 = t1;
当你在这里创建两个不同的对象时,hashcode不相等,因为它们不引用相同的object
,hashcodes
必须是不同的
记住
MUST
相等答案 2 :(得分:1)
这是因为Java中的equals
和hashCode
的默认实现。
JVM无法知道您如何确定两个对象是否相同。它的作用是使用内存引用。因此,默认情况下,equals
和hashCode
方法会比较内存引用;即两个不同的对象从不 .equals
。
如果您想覆盖此行为(如果您希望使用Collection
,建议您这样做),那么您需要做的就是实现自己的equals
和{{ 1}}方法。
答案 3 :(得分:1)
问题是t1和t2不是同一个对象,它们是不同的对象。使用new创建的所有对象都是不同的对象。默认的hashCode()实现通常会为不同的对象返回不同的哈希码。请参阅Object.hashCode API。