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
.