Why objects are not same added to hashset with same value, even hashCode and equals are overriden

450 views Asked by At

Here is the code which produces hashset size 3 instead 2

package dump.test;
import java.util.*;
public class WrappedString {
    private String s;
    public WrappedString(String s) { this.s = s; }
    public static void main(String[] args) {
        HashSet<Object> hs = new HashSet<Object>();
        WrappedString ws1 = new WrappedString("aardvark");
        WrappedString ws2 = new WrappedString("aardvark");
        String s1 = new String("aardvark");
        String s2 = new String("aardvark");
        hs.add(ws1); hs.add(ws2); hs.add(s1); hs.add(s2);
        System.out.println(hs.size()+hs.toString()); 
    }
    public boolean equals(Object aSong) {
        String s = aSong.toString();
        System.out.println(s);
        return s.equals(this.s);
    }
    public int hashCode() {
        System.out.println(this.s + "-" + this.s.hashCode());
        return this.s.hashCode();
    }
    /*public int compareTo(Object aSong) {
        String s = aSong.toString();
        return this.s.compareTo(s);
    }*/
}

It always print below output if equals and hashCode are overridden enter image description here

you can see both objects having same code in output but counted as different and produced count as 3

this is if we do not override equals and hashCode enter image description here

Please assist me how this works.

3

There are 3 answers

0
Anil Jeeyani On

adding

public String toString() { return this.s; }

cleared my confusion. Previously it couldn't convert true value from casting object to string and needed to override toString to return underlying value.

2
Sebastian On

The problem is that your case is not symmetric. If the implementation decides to invoke equals on the String instance with your class as an argument, it will definitely return false and thus your code will not always work.

3
jpkroehling On

From the JavaDoc for the Set interface:

A collection that contains no duplicate elements. More formally, sets contain no pair of elements e1 and e2 such that e1.equals(e2), and at most one null element. As implied by its name, this interface models the mathematical set abstraction.

So, HashSet checks the equals(Object) before adding the new element. As the second String is equal to the first, it's not added. On your WrappedString, you are not overriding the equals(Object), so, you are using the one inherited from Object, which simply checks the object IDs (659e0bfd and 2a139a55 in your case).