简体   繁体   中英

If the hashcode() creates hashcode based on the address of the object, how can two different objects with same contents create the same 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?

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

  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.

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM