7

here is my code :

public class testGui {



    public static void main(String[] arg){
        class TESTS{
            String t;

            public TESTS(String t){
                this.t = t;
            }

            @Override
            public boolean equals(Object x){
                System.out.println("My method is called...");
                if(x instanceof TESTS){
                    TESTS zzz = (TESTS) x;
                    return zzz.t.compareTo(t)==0;
                }
                else return false;
            }
        }
        HashSet<TESTS> allItems = new HashSet<TESTS>();
        allItems.add(new TESTS("a"));
        allItems.add(new TESTS("a"));
        System.out.println(allItems.contains(new TESTS("a")));
    }

}

I do not get why the hashset contains method is not calling my equals method as mentionned in their specifications :

More formally, adds the specified element, o, to this set if this set contains no element e such that (o==null ? e==null : o.equals(e))

My code is returning false and not going into my equals method.

Thanks a lot for answering!

Abbadon
  • 137
  • 1
  • 6

4 Answers4

13

When you override equals, you must also override hashCode. Otherwise, equal objects will have different hash codes and be considered unequal.

It is also strongly recommended not to override only hashCode. But this is not essential, as unequal objects can have the same hash code.

Matthew Flaschen
  • 278,309
  • 50
  • 514
  • 539
  • 2
    They won't be considered unequal. It's just that the HashSet won't even invoke the equals method because it only does it for hashCodes leading to the same bucket. And overriding only hashCode doesn't have any sense, since HashSet will always call equals for objects having the same hashCodes. – JB Nizet Mar 31 '11 at 22:34
  • @JB, yes, the fact that they lead to different buckets means they are considered 'unequal' (considered different objects). I am not referring to the `equals` method when I use that term. I also agree overriding only `hashCode` is illogical, which is why I strongly recommended against it. However, it doesn't break the contract. – Matthew Flaschen Apr 01 '11 at 00:41
  • 1
    It would be nice if the java documentation mentioned that hashcode is called first. I just got burned by this issue in java 5. – Aaron Jul 25 '11 at 15:59
  • @Aaron, not only would it be nice, I would argue that at the moment, it's downright incorrectly documented, and this has persisted through to current-day Java. It says that the contains and add methods are equivalent to Objects.equals, but they demonstrably are not. – Tim M. Feb 10 '19 at 05:09
7

The HashSet depends on the HashCode of each object. Before the equals method is called, the hashCode method will be called. If hashcodes are equal, then the hashset deems it worthy of evaluating the equals method.

Implement a hashcode method such that if a.equals(b) == true, then a.hashCode() == b.hashCode()

and it should start working as you would expect.

rahul
  • 1,281
  • 2
  • 12
  • 29
3

You should also implement hashCode, so that it is consistent with equals. HashSet uses the hashCode method to decide which bucket to put an item into, and calls equals only when the hash code of two items are the same.

Effective Java, 2nd Edition discusses this rule (and the consequences of breaking it) in Item 9: Always override hashCode when you override equals.

Péter Török
  • 114,404
  • 31
  • 268
  • 329
  • Thanks a lot guys, that was really helpful, I found the answer before you answered (didn't know how to cancell the question), but what you wrote is what I done and it solved my problem ;). – Abbadon Apr 02 '11 at 10:24
0

As most of the comments have been... just override the hashcode method (sample below) and you should be good.

@Override
        public int hashCode() {
            return t.hashCode()*31;
        }
Prasanna
  • 34
  • 2