0

Friends, I found a question like this in HashSets.

public class _235 {
    private String s;
    public _235(String s){
    this.s=s;
    }
     public static void main(String[] args){

         HashSet<Object> hs=new HashSet<Object>();
         _235 ws1=new _235("ABC");
         _235 ws2=new _235("ABC");       

            String s1=new String("ABC");
            String s2=new String("ABC");

            hs.add(ws1);
            hs.add(ws2);
            hs.add(s1);
            hs.add(s2);

         System.out.println(hs.size());

     }
}

When I checked both ws1 and ws1 have added to the HashSet but not from s1 and s2 only one String has added. Since w1 and w2 have not gone through equal() I believe HashSet doesn't recognize them as equal 2 objects. But why doesn't this become same for Strings s1 and s2 as well. How it hs been identified they are as meaningfully equal objects. Please kindly explain.

user3789200
  • 1,166
  • 2
  • 25
  • 45
  • 1
    To understand what happens, examine what `equals` and `hashCode` methods of `_235` do. Hint: it uses the superclass methods, when you don't override them. – hyde Aug 10 '14 at 10:02

2 Answers2

2

HashSet requires your custom class to override equals() and hashcode() methods which are used internally to detect duplicate elements.

String class has this implementation but your custom class _235 does not have one.

Note: It is important to override both equals() and hashcode() and not just one of them or else results could be unpredictable when used with hash-based collections.

You must override hashCode() in every class that overrides equals(). Failure to do so will result in a violation of the general contract for Object.hashCode(), which will prevent your class from functioning properly in conjunction with all hash-based collections, including HashMap, HashSet, and Hashtable.

from Effective Java, by Joshua Bloch

Here is a link with good explanation.

Community
  • 1
  • 1
Ankur Shanbhag
  • 7,746
  • 2
  • 28
  • 38
1

First of all String has overridden its equals method that checks for the content of it not through hashCode so when you add in the parameter of String "ABC" and other one "ABC" it will return true if the contents are the same.

String equals method:

public boolean equals(Object anObject) {
      if (this == anObject) {
          return true;
      }
      if (anObject instanceof String) {
          String anotherString = (String)anObject;
          int n = count;
          if (n == anotherString.count) {
              char v1[] = value;
              char v2[] = anotherString.value;
              int i = offset;
              int j = anotherString.offset;
              while (n-- != 0) {
                  if (v1[i++] != v2[j++])
                      return false;
              }
              return true;
          }
      }
      return false;
  }

While on objects they only used the default equals method which use the hashCode of the object

Object equals method:

public boolean equals(Object obj) {
return (this == obj);
}

In your result:

the wsi and ws2 will always return false when executing equals method because they are located on different memory location while the s1 and s2 will return true when they have the same content thus only adding one instance of it to the HashSet, that HashSet does not allowed duplicates.

Rod_Algonquin
  • 26,074
  • 6
  • 52
  • 63