如果 hashcode() 根据对象的地址创建哈希码,那么具有相同内容的两个不同对象如何创建相同的哈希码?

If the hashcode() creates hashcode based on the address of the object, how can two different objects with same contents create the same hashcode?

当你阅读对象 class 中 hashCode() 的描述时,它说

If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.

我看过一篇文章,它说如果一个对象的 hashcode() 在不同的环境中运行,即使它们的内容相同,它也可以提供不同的整数值。

String class 的 hashcode() 不会发生这种情况,因为 String class 的 hashcode() 根据对象的内容创建整数值。相同的内容总是创建相同的哈希值。

但是,如果对象的哈希值是根据它在内存中的地址计算的,就会发生这种情况。而文章作者说Objectclass是根据对象在内存中的地址计算出对象的hash值

在下面的示例中,对象 p1 和 p2 具有相同的内容,因此它们上的 equals() return 为真。 但是,这两个对象内存地址不同,怎么会return哈希值一样呢?

示例代码如下:main()

 Person p1 = new Person2("David", 10);
 Person p2 = new Person2("David", 10);

 boolean b = p1.equals(p2);

 int hashCode1 = p1.hashCode();
 int hashCode2 = p2.hashCode();

这里是重写的 hashcode()

 public int hashCode(){
       return Objects.hash(name, age);
 }

文章内容有误吗?

如果有一个 hashCode() 可以根据实例的地址计算哈希值,它们的用途是什么?

此外,如果它真的存在,它违反了对象class的hashCode()指定的条件。那么我们应该如何使用hashCode()呢?

这是每个程序员需要为他们定义的(比如)MyClass 对象做出的设计决策:

你希望两个不同的对象可以“相等”吗?

如果你这样做,那么首先你必须实施 MyClass.equals() 以便它为你的目的提供正确的平等概念。这完全在你手中。

那么你应该这样实现 hashCode,如果 A.equals(B),则 A.hashCode() == B.hashCode()。您明确不想使用Object.hashCode()。

如果您不希望不同的对象永远相等,则不要实现 equals() 或 hashCode(),使用 Object 为您提供的实现。对于对象 A 和对象 B(不同的对象,而不是对象的子类),那么 A.equals(B) 永远不会出现,因此 A.hashCode() 永远不会相同是完全可以的作为 B.hashCode().

  1. 这篇文章是错误的,没有涉及内存地址(顺便说一下,地址在对象的生命周期中会发生变化,所以它被抽象为引用)。您可以将默认的 hashCode 视为一种方法,该方法 return 是一个随机整数,对于同一对象始终相同。

  2. 默认 equals(继承自 Object)与 == 完全相同。因为有一个条件(类 需要 HashSet 等工作)说明 when a.equals(b) then a.hashCode == b.hashCode,那么我们需要一个默认的hashCode,它只需要有一个属性:当我们调用它两次时,它必须return相同的数字。

  3. 默认的 hashCode 完全存在,因此您提到的条件得到支持。 returned 的值并不重要,重要的是它永远不会改变。

没有p1和p2内容不一样

如果你这样做 p1.equals(p2) 那将是错误的,所以内容不一样。

如果您希望 p1 和 p2 相等,您需要从对象中实现 equals 方法,以比较它们的内容的方式。如果你实现了 equals 方法,那么你也必须实现 hashCode 方法,这样如果 equals return 为真,那么对象有相同的 hashCode().

我认为你误解了这个说法:

If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.

“必须”这个词意味着你,程序员,被要求写一个hashCode()方法,它总是为两个对象产生相同的hashCode值,这两个对象根据它们的equals(Object)方法。

如果你不这样做,你就写了一个损坏的对象,将无法使用任何使用散列码的class,尤其是未排序的集合和映射。

I've read an article and it says that an object's hashcode() can provide different integer values if it runs in different environments even though their content is the same.

是的,hashCode() 可以在不同的运行时提供不同的值,对于不覆盖 hashCode() 方法的 class。

… how come these two objects return the same hash value when their memory addresses are different?

因为你告诉他们。您覆盖了 hashCode() 方法。

If there is a hashCode() that calculates a hash value based on the instance's address what is the purpose of them?

用处不大。这就是为什么强烈建议程序员重写该方法,除非他们不关心对象标识。

Also, if it really exists, it violates the condition that Object class's hashCode() specifies. How should we use the hashCode() then?

不,它没有。 The contract states:

  • 只要在 Java 应用程序的执行期间对同一个对象多次调用,hashCode 方法必须始终 return 相同的整数,前提是没有使用任何信息在equals 比较对象上修改。从一个应用程序的一次执行到同一应用程序的另一次执行,该整数不需要保持一致。

只要对象 class return 中定义的 hashCode 方法在 Java 运行时期间具有相同的值,它就是合规的。

合同还说:

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

equals 方法报告它们实际上相等的两个对象必须return 相同的 hashCode。 Object class 的任何类型不是 Object 的子 class 的实例只等于它自己,不能等于任何其他对象,所以它的任何值 returns 都是有效的,只要它在 Java 运行时的整个生命周期内保持一致。