The default hashcode implementation returns different values ​​for objects constructed in the same way.

Here I write one example code:

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; } } 

Now I create two objects as shown below:

 Test t1= new Test(4,5); Test t2 = new Test(4,5); 

But when I print t1.hashcode () and t2.hashcode (), they give different values. But according to the general java contact, they should return the same value. In fact, when I do the same with String or Integer, they return the same hashcode (). Can someone explain why hashcode is different for objects t1 and t2?

+4
source share
4 answers

But according to the general java contact, they should return the same value.

The Java contract equals-hashCode requires that if two objects are equal Object.equals , they must have the same hash code from Object.hashCode . But the default implementation of Object.equals is a reference , and therefore two instances are the same if and only if they are the same instance.

Therefore, in particular, your two instances t1 and t2 are actually not equal, because you did not redefine Object.equals . They are not equal in quality of links and, therefore, are not equal in Object.equals , and therefore it is permissible for hashCode to return different values. In fact, the contract explicitly states the following:

It is not required that if two objects are unequal according to the equals(java.lang.Object) method equals(java.lang.Object) , then calling the hashCode method for each of the two objects must produce different integer results.

Thus, we have no breach of the equals-hashCode contract.

So, for your objects, if you want different instances to be equal for the logical definition of equality, you need to redefine 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; } 

And the equals-hashCode contract requires that you redefine Object.hashCode too, or you will encounter some nasty bugs:

  @Override public int hashCode() { int hash = 17; hash = 31 * hash + this.i; hash = 31 * hash + this.j; return hash; } 

What the contract says:

If two objects are equal according to the equals(Object) method, calling the hashCode method for each of the two objects should yield the same integer result.

Let's see if we have met this requirement here. If x and y are instances of Test and satisfy x.equals(y) is true , we have xi == yi and xj == yj . Then, obviously, if we call x.hashCode() and y.hashCode() , we have the invariant that in each line of execution in Test.hashCode we will have hash with the same value. Clearly, this is true on the first line, since hash will be 17 in both cases. It will hold the second line since this.i will return the same value as this == x or this == y , because xi is equal to yi . Finally, on the penultimate line, we will still have hash equal for both calls, because xj is equal to yj also true.

Please note that there is one last part of the contract that we have not talked about yet. This requirement is that hashCode returns a consistent value during one run of a Java application:

Whenever it is called on the same object more than once during the execution of a Java application, the hashCode method must return the same integer sequentially if the information used for equal object mappings does not change.

The need for this is obvious. If you change the return value from hashCode during one run of the same application, you can lose your objects in the hash table data structures that use hashCode to track objects. In particular, this is precisely why mutating objects, which are keys in hash table data structures, are pure evil; do not do this. I would go so far as to claim that they should be immutable objects.

In fact, when I do the same with String or Integer , they return the same hashcode() .

They are both overridden by Object.equals and Object.hashCode .

+18
source

You have not redefined the equals method in your class, so the default value for the Object class is used. The class methods of the object simply check the links whether they refer to the same object or not.

 Test t1 = new Test(4,5); Test t2 = new Test(4,5); 

- two different objects, if you do not redefine the equals method here, they will be equal if and only if you

 Test t2 = t1; 

Since you are creating two different objects here, hashcode which is NOT equal because they are not the same Object , hashcodes must be different Remember

  • If two objects are equal, then their hash code MUST will be equal
  • But if the hash codes are equal, then the objects do not need to be equal
+3
source

This is due to the default implementation of equals and hashCode in Java.

The JVM does not know how you decide that two objects are the same. It uses memory references. Thus, by default, the equals and hashCode methods compare memory references; that is, two different objects: never .equals .

If you want to override this behavior (and it is recommended to do this if you want to use Collection , for example), you only need to implement your equals and hashCode methods.

+1
source

The problem is that t1 and t2 are not the same object, they are another object. All objects created with new ones are different objects. And the default implementation of hashCode () usually returns different hash codes for different objects. See API Object.hashCode.

+1
source

Source: https://habr.com/ru/post/1486733/


All Articles