Java hashcode的默认实现为以相同方式构造的对象返回不同的值

Java hashcode的默认实现为以相同方式构造的对象返回不同的值,java,Java,我在这里编写一个示例代码: 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

我在这里编写一个示例代码:

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的一般联系,它们应该返回相同的值。 事实上,当我对字符串或整数执行相同的操作时,它们返回的是相同的hashcode()。有人能解释为什么t1和t2对象的哈希代码不同吗

但根据java的一般联系,它们应该返回相同的值

Java的
equals hashCode
契约要求,如果两个对象的值等于,那么它们必须具有相同的hashCode。但是
Object.equals
的默认实现是referenceequality,因此两个实例是相同的当且仅当它们是相同的实例时

因此,特别是,您的两个实例
t1
t2
实际上并不相等,因为您没有重写
Object.equals
。它们作为引用不相等,因此每个
对象不相等。等于
,因此
hashCode
可能返回不同的值是可以接受的。事实上,合同明确规定如下:

根据
equals(java.lang.Object)
方法,如果两个对象不相等,则对两个对象中的每一个调用
hashCode
方法都必须产生不同的整数结果

因此,我们没有违反这里的
等于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;
 }
等于hashCode
契约要求您也重写
对象。hashCode
,否则您会遇到一些讨厌的bug:

 @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
equals
y.j
也是真的

请注意,我们还没有讨论合同的最后一部分。这是要求
hashCode
在Java应用程序的单个执行期间返回一致的值:

在Java应用程序的执行过程中,每当在同一对象上多次调用它时,
hashCode
方法必须一致地返回相同的整数,前提是不修改对象上的equals比较中使用的信息

这样做的必要性是显而易见的。如果在同一应用程序的单个执行过程中更改
hashCode
的返回值,则可能会丢失使用
hashCode
跟踪对象的类似哈希表的数据结构中的对象。特别是,这就是为什么在类似哈希表的数据结构中改变作为键的对象是纯粹的邪恶;不要这样做。我甚至认为它们应该是不变的对象

事实上,当我对
String
Integer
执行相同操作时,它们返回的是相同的
hashcode()


它们都重写了
Object.equals
Object.hashCode
这是因为Java中默认实现了
equals
hashCode

JVM无法知道如何确定两个对象是相同的。它所做的是使用内存引用。因此,默认情况下,
等于
hashCode
方法比较内存引用;i、 e.两个不同的对象是从不
。等于


如果要覆盖此行为(例如,如果希望使用
Collection
s,建议您这样做)然后,您需要做的就是实现自己的
equals
hashCode
方法。

您还没有覆盖类中的
equals
方法,因此将使用属于
对象的默认方法。
对象类方法只是检查引用是否引用同一对象

Test t1 = new Test(4,5);
Test t2 = new Test(4,5);
是两个不同的对象,如果不重写此处的
equals
方法,则当且仅当您重写时,它们才会相等

Test t2 = t1;
当您在这里创建两个不同的对象时,hashcode不相等,因为它们引用的对象不同,
hashcodes
必须不同 记得吗

  • 如果两个对象相等,则它们的hashcode
    必须相等
  • 但是如果hashcode是相等的,那么对象就没有必要相等

    • 问题在于t1和t2不是同一个对象,而是不同的对象。使用“新建”创建的所有对象都是不同的对象。默认的hashCode()实现通常会为不同的对象返回不同的哈希代码。请参阅Object.hashCode API。

      您是否阅读了d