default implementation of hashcode returns different values for objects constructed the same way

╄→гoц情女王★ 提交于 2021-02-19 02:43:47

问题


Here I am writing one sample 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 am creating two objects as bellow:

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

But when i am printing t1.hashcode() and t2.hashcode() they are giving different values. But as per java's general contact they should return same value. In fact, when i am doing same thing with String or Integer they are returning same hashcode(). Can anyone please explain why hashcode is different for t1 and t2 object?


回答1:


But as per java's general contact they should return same value.

Java's equals-hashCode contract requires that if two objects are equal by Object.equals, they must have the same hashcode from Object.hashCode. But the default implementation of Object.equals is reference equality, 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 in fact not equal because you have not overridden Object.equals. They are not equal as references, and therefore not equal per Object.equals, and therefore it is acceptable for hashCode to possibly return different values. In fact, the contract explicitly says the following:

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

Thus, we do not have a violation of the equals-hashCode contract here.

So, for your objects, if you want different instances to be equal per a logical definition of equality, you need to override 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 override Object.hashCode too or you'll run into some nasty bugs:

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

What does the contract say:

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.

Let's see if we have satisfied this requirement here. If x and y are instances of Test and satisfy x.equals(y) is true, we have that x.i == y.i and x.j == y.j. Then, clearly, if we invoke x.hashCode() and y.hashCode() we have the invariant that at each line of execution in Test.hashCode we will have hash holding the same value. Clearly this is true on the first line since hash will be 17 in both cases. It will hold on the second line since this.i will return the same value whether this == x or this == y because x.i equals y.i. Finally, on the penultimate line, we will still have hash being equal across both invocations because x.j equals y.j is true as well.

Note that there is one last piece of the contract that we haven't discussed yet. This is the requirement that hashCode return a consistent value during a single execution of a Java application:

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.

The necessity of this is obvious. If you change the return value from hashCode during a single execution of the same application, you could lose your objects in hashtable-like data structures that use hashCode to keep track of objects. In particular, this is why mutating objects that are keys in hashtable-like data structures is pure evil; don't do it. I would go so far as to argue that they should be immutable objects.

In fact, when i am doing same thing with String or Integer they are returning same hashcode().

They've both overridden Object.equals and Object.hashCode.




回答2:


You have not overridden the equals method in your class so the default one will be used that belongs to Object class. Object class methods simply checks for the references whether they are referring to the same object or not.

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

are two different objects, if you don't override the equals method here, they will be equal if and only if you do

Test t2 = t1;

As you are creating two different objects here, hashcode which are NOT equal because they don't refer to the same object, hashcodes must be differnt Remember

  • If two objects are equal, then their hashcode MUST be equal
  • But if hashcodes are equal, then its not necessary that objects should be equal



回答3:


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

The JVM has no way of knowing how you decide that two objects are the same. What it does is use memory references. So, by default, the equals and hashCode methods compare memory references; i.e. two different objects are never .equals.

If you want to override this behaviour (and it is recommended you do so if you wish to use Collections for example) then all you need to do is implement your own equals and hashCode methods.




回答4:


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



来源:https://stackoverflow.com/questions/17159881/default-implementation-of-hashcode-returns-different-values-for-objects-construc

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!