1

This is my example code to test HashSet. I expect that the result is [3K,1K] but the this code results in [1K,3K,3K]

Could you let me know why the code not call equals?

import java.util.HashSet;

class SutdaCard{

    private int num;
    private boolean isKwang;

    SutdaCard(){
        this(1,true);
    }
    SutdaCard(int num, boolean isKwang){
        this.num = num;
        this.isKwang = isKwang;
    }

    public String toString(){
        return num+(isKwang ? "K":"");
    }

    public boolean equals(Object obj){
        String compareValue = obj.toString();
        String thisValue = toString();

        System.out.println("equals");

        return thisValue.equals(compareValue);
    }

    public int hashcode(){
        return toString().hashCode();
    }

}
class exercise11_11 {
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub      

        HashSet<SutdaCard> set = new HashSet<SutdaCard>();


        set.add(new SutdaCard(3,true));
        set.add(new SutdaCard(3,true));
        set.add(new SutdaCard(1,true));

        System.out.println(set);

    }

}
Pshemo
  • 122,468
  • 25
  • 185
  • 269
500004dolkong
  • 725
  • 3
  • 12
  • 19
  • 9
    If this is your code, then you have a typo in `hashCode` method name (lowercase `c`). – Pavel Horal Feb 26 '14 at 14:42
  • 1
    and as a consequence of what @PavelHoral noticed, when HashSet calls the real hashCode, it gets a different value for each of your three items, and as per the specs they thus can't be equals (so equals is not called) – Gorkk Feb 26 '14 at 14:43
  • 4
    and use @Override annotation to make sure, that you are overriding smth – arghtype Feb 26 '14 at 14:43
  • 1
    If you override methods (here it is hashCode and equals) you should always annotate these methods with @Override. The compiler then checks, whether the method is indeed overridden. In your case, you then get a compiler error for the method hashcode, as this does not override any method from class Object. – Seelenvirtuose Feb 26 '14 at 14:45
  • See also https://stackoverflow.com/questions/14504901/when-does-hashset-add-method-calls-equals – Raedwald Nov 21 '18 at 08:49

1 Answers1

6

You haven't overridden hashCode() properly. Try:

@Override
public int hashCode() {
    return this.toString().hashCode();
}

Since the Set uses the hashCode() from Object in your code, the two SutdaCards hash codes won't match, and equals() is never called.

If you add the @Override annotation, the compiler will check that you are actually overriding something, and generate a warning if you have a spelling error.

Keppil
  • 45,603
  • 8
  • 97
  • 119
  • 1
    but this is implicitly available ? your solution is with "this" keyword or "@override" ? – Android Killer Feb 26 '14 at 14:44
  • 2
    For the same reason you should also add `@Override` to the `equals` and `toString` method. All those methods override the default from the [Java Object class](http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html). – SebastianH Feb 26 '14 at 14:46