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

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

Please assist me how this works.
                        
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.