0
votes

how hashcode or hashmap works, if we override hashcode which returns always a constant and overridden equals methods return false, how it able to identify the exact object while returning or deleting? time bean forgot about the performance all that stuff, my question how it able to identify exact object, let I explain a bit more , i have a person class with two fields and have overridden hashcode which returns always 1 and overridden equals method which returns false, have created 3 objects, object 1 -- id 10 name AAAA, object 2 -- id 20, name BBB, object 3 -- id 30 ,name CCC, I have added all three of objects to hashSet, after that I removed object 2, here how its identifying exact object (20, BBB)

2

2 Answers

4
votes

Well, constant hashcode is valid and "only" a performance problem when using HashMap/HashSet or other code that uses it to optimize comparisons/searches.

An equals() implementation that always returns false, however, breaks the contract of equals and will lead to problems/surprising behavior with many types of collections.

From the JavaDocs of equals:

The equals method implements an equivalence relation on non-null object references:

  • It is reflexive: for any non-null reference value x, x.equals(x) should return true.
  • It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
  • It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.
  • It is consistent: for any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified.
  • For any non-null reference value x, x.equals(null) should return false.

An return false implementation breaks the first requirement.

From the JavaDocs of hashcode:

  • 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. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.

As @Mensur Qulami pointed out in the comments, it may still appear to work correctly with HashMap if your implementation uses reference comparison with == to optimize the searches for nodes.

From OpenJDK 12 HashMap.getNode(int hash, Object key):

((k = first.key) == key || (key != null && key.equals(k))))

so this implementation checks reference equality before trying equals(), but that is not guaranteed.

The JavaDocs for HashMap.get define this strictly in terms of equals()

More formally, if this map contains a mapping from a key k to a value v such that (key==null ? k==null : key.equals(k)), then this method returns v; otherwise it returns null.

(this is equivalent if the implementation of equals fulfills the contract above, so the optimization done by OpenJDK is valid)

1
votes

It's still able to remove the object, even though equals returns false, because == still returns true (== compares the actual object reference, and is not affected by the equals implementation).

HashSet remove ultimatly calls HAshMap, removeNode which contains this comparison to see if the value is found.

            if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))

It compares the hashCode, which is always equal since it's a constant, and then first uses == to compare. If the key is not the same object (ie. == is false), only then equals is used to check if they are equal.

If you would create a new object with the same value, you would never be able to use it to remove the value from the set, but when you use the same object you still can because of ==