5

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?

Raedwald
  • 46,613
  • 43
  • 151
  • 237
user2392631
  • 497
  • 8
  • 15
  • 7
    Did you read the documentation? http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#hashCode(). Here's a hint: Is it true that `t1.Equals(t2)` in your example? – rliu Jun 18 '13 at 03:01
  • They aren't the same object. Not a real question. – user207421 Jun 18 '13 at 04:00
  • http://stackoverflow.com/questions/16105420/java-object-hashcode-address-or-random may be this can help – Mikhail Jun 21 '13 at 06:18

4 Answers4

20

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.

jason
  • 236,483
  • 35
  • 423
  • 525
  • Equals method of object class uses '==' operator to check the equality. Hence it will only return true if both the references are pointing to the same object, which is not the case in your program. – Darshan Mehta Jun 18 '13 at 03:04
  • 5
    @DarshanMehta I think your comment is in the wrong place. Jason has already stated this. – BLaZuRE Jun 18 '13 at 03:05
3

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
Prasad Kharkar
  • 13,410
  • 5
  • 37
  • 56
1

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.

Boris the Spider
  • 59,842
  • 6
  • 106
  • 166
1

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.

Evgeniy Dorofeev
  • 133,369
  • 30
  • 199
  • 275