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

huangapple go评论116阅读模式
英文:

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

问题

当您阅读Object类中hashCode()方法的描述时,它说道:

> 如果根据equals(Object)方法两个对象是相等的,那么在这两个对象上调用hashCode方法必须产生相同的整数结果。

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

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

然而,如果对象的哈希值是基于其在内存中的地址计算的,则可能会发生。文章的作者称,Object类根据对象在内存中的地址计算对象的哈希值。

在下面的示例中,对象p1和p2具有相同的内容,因此对它们调用equals()会返回true。但是,当它们的内存地址不同的情况下,这两个对象如何返回相同的哈希值呢?

以下是示例代码: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()方法,它的目的是什么?

而且,如果真的存在这样的方法,它违反了Object类的hashCode()方法规定的条件。那我们应该如何使用hashCode()方法呢?

英文:

When you read the description of hashCode() in the Object class, it says that

> 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.

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.

It does not happen with String class's hashcode() because the String class's hashcode() creates integer value based on the content of the object. The same content always creates the same hash value.

However, it happens if the hash value of the object is calculated based on its address in the memory. And the author of the article says that the Object class calculates the hash value of the object based on its address in the memory.

In the example below, the objects, p1 and p2 have the same content so equals() on them returns true.
However, how come these two objects return the same hash value when their memory addresses are different?

Here is the example code: 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();

Here is the overriden hashcode()

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

Is the article's content wrong?

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?

答案1

得分: 1

以下是每个程序员在定义(比如说)MyClass 类时需要做出的设计决策:

你是否希望两个不同的对象能够“相等”?

如果是的话,首先你必须实现 MyClass.equals() 方法,以便它对于你的目的提供正确的相等性概念。这完全取决于你自己。

然后,你应该实现 hashCode 方法,使得如果 A.equals(B),那么 A.hashCode() == B.hashCode()。你明确地希望使用 Object.hashCode() 方法。

如果你不希望不同的对象永远相等,那么就不要实现 equals() 和 hashCode() 方法,直接使用 Object 提供的默认实现。对于对象 A 和对象 B(不同的对象,且不是 Object 的子类),永远不会出现 A.equals(B) 的情况,因此 A.hashCode() 从不会与 B.hashCode() 相同。

英文:

Here's the design decision every programmer needs to make for objects they define of (say) MyClass:

Do you want it to be possible for two different objects to be "equal"?

If you do, then firstly you have to implement MyClass.equals() so that it gives the correct notion of equality for your purposes. That's entirely in your hands.

Then you're supposed to implement hashCode such that, if A.equals(B), then A.hashCode() == B.hashCode(). You explicitly do not want to use Object.hashCode().

If you don't want different objects to ever be equal, then don't implement equals() or hashCode(), use the implementations that Object gives you. For Object A and Object B (different Objects, and not subclasses of Object), then it is never the case that A.equals(B), and so it's perfectly ok that A.hashCode() is never the same as B.hashCode().

答案2

得分: 1

  1. 这篇文章是错误的,与内存地址无关(顺便说一下,对象的生命周期内地址是可以改变的,因此它被抽象为引用)。你可以将默认的 hashCode 视为返回随机整数的方法,对于同一对象始终相同。

  2. 默认的 equals 方法(从 Object 继承而来)的工作方式与 == 完全相同。由于存在一个条件(对于像 HashSet 等工作的类来说是必需的),即 当 a.equals(b) 时 a.hashCode == b.hashCode,因此我们需要一个默认的 hashCode,它只需要具有一个属性:当我们调用它两次时,必须返回相同的数字。

  3. 默认的 hashCode 存在的目的正是为了维持你提到的条件。返回的值并不重要,重要的是它永远不会改变。

英文:
  1. The article is wrong, memory address is not involved (btw. the address can change during the lifecycle of objects, so it's abstracted away as a reference). You can look at the default hashCode as a method that returns a random integer, which is always the same for the same object.

  2. Default equals (inherited from Object) works exactly like ==. Since there is a condition (required for classes like HashSet etc. to work) that states when a.equals(b) then a.hashCode == b.hashCode, then we need a default hashCode which only has to have one property: when we call it twice, it must return the same number.

  3. The default hashCode exists exactly so that the condition you mention is upheld. The value returned is not important, it's only important that it never changes.

答案3

得分: 1

没有 p1 和 p2 的内容相同

如果你执行 p1.equals(p2),结果将会是 false,所以内容不相同。

如果你希望 p1 和 p2 相等,你需要实现对象的 equals 方法,以一种比较它们内容的方式进行比较。并且如果你实现了 equals 方法,那么你还必须实现 hashCode 方法,以便如果 equals 返回 true,则对象具有相同的 hashCode()。

英文:

No p1 and p2 does not have the same content

If you do p1.equals(p2) that will be false, so not the same content.

If you want p1 and p2 to equal, you need to implement the equals methods from object, in a way that compare their content. And IF you implement the equals method, then you also MUST implement the hashCode method, so that if equals return true, then the objects have the same hashCode().

答案4

得分: 1

我认为你对这个表述有误解:

> 如果两个对象根据 equals(Object) 方法是相等的,那么在这两个对象的每个对象上调用 hashCode 方法必须产生相同的整数结果。

这里的“必须”意味着作为程序员,你需要编写一个 hashCode() 方法,该方法始终为两个根据它们的 equals(Object) 方法相等的对象生成相同的 hashCode 值。

如果不这样做,你编写的对象会出现问题,在使用哈希码的任何类,特别是未排序的 Set 和 Map 类中将“无法正常工作”。

> 我读过一篇文章,上面说如果一个对象的 hashcode() 在不同的环境中运行时可能会提供不同的整数值,即使它们的内容相同。

是的,如果一个类没有重写 hashCode() 方法,它的 hashCode() 可能在不同的运行时提供不同的值。

> … 为什么这两个对象在其内存地址不同的情况下返回相同的哈希值?

因为你告诉它们如何做。你重写了 hashCode() 方法。

> 如果存在一个根据实例地址计算哈希值的 hashCode(),它的目的何在?

这个方法没有太多的用途。这就是为什么强烈建议程序员重写这个方法的原因,除非他们不关心对象标识。

> 此外,如果它真的存在,它就违反了 Object 类的 hashCode() 所指定的条件。那我们应该如何使用 hashCode() 呢?

不,它没有违反条件。合同规定

  • 在 Java 应用程序执行过程中对同一个对象多次调用 hashCode 方法时,只要在对象上用于 equals 比较的信息未被修改,该方法必须始终一致地返回相同的整数。这个整数在一个应用程序的多次执行之间没有必要保持一致。

只要 Object 类中定义的 hashCode 方法在 Java 运行时的整个期间内返回相同的值,它就是合规的。

合同还指出:

  • 如果两个对象根据 equals(Object) 方法是相等的,那么在这两个对象的每个对象上调用 hashCode 方法必须产生相同的整数结果。

根据 equals 方法报告它们实际上是相等的两个对象必须返回相同的 hashCode。任何类型不是 Object 的子类的 Object 类的实例只与自身相等,不能与任何其他对象相等,因此它返回的任何值都是有效的,只要在 Java 运行时的整个生命周期内保持一致。

英文:

I think you have misunderstood this statement:

> 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.

The word “must” means that you, the programmer, are required to write a hashCode() method which always produces the same hashCode value for two objects which are equal to each other according to their equals(Object) method.

If you don’t, you have written a broken object that will not work with any class that uses hash codes, particularly unsorted Sets and Maps.

>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.

Yes, hashCode() can provide different values in different runtimes, for a class which does not override the hashCode() method.

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

Because you told them to. You overrode the hashCode() method.

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

It doesn’t have a lot of use. That’s why programmers are strongly recommended to override the method, unless they don’t care about object identity.

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

No it does not. The contract states:

  • 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. This integer need not remain consistent from one execution of an application to another execution of the same application.

As long as the hashCode method defined in the Object class returns the same value for the duration of the Java runtime, it is compliant.

The contract also says:

  • 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.

Two objects whose equals method reports that they are effectively equal must return the same hashCode. Any instance of the Object class whose type is not a subclass of Object is only equal to itself and cannot be equal to any other object, so any value it returns is valid, as long as it is consistent throughout the life of the Java runtime.

huangapple
  • 本文由 发表于 2020年8月18日 04:48:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/63458443.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定