Confusion regarding hashset, hashmap, hashcode, equals

902 views Asked by At

Property of SET is it doesnt allow duplicate elements .

but referring to SCJP: When hashset or linkedhashset is used. when you add objects you must override hashcode else you may end up with duplicate elements in the set.

boolean[] b=new boolean[5];
Set s=new HashSet();
b[0]=s.add("a");
b[1]=s.add("a");

here the output is True , False I wonder how come the output is false when you have not overridden the hashcode. But when you override hashcode, you must overrride equals().

DOes Collection interface provide default equals() method?

I am not able to understand,

5

There are 5 answers

6
Eran On

First of all, String does override hashCode and equals, so your code uses String's version of those methods (since you are adding Strings to your HashSet).

Second of all, even if it didn't, in your example, "a" is interned, so both calls to s.add("a") are adding the exact same object, so even Object's default implementation of hashCode and equals would have given the same results.

2
Anders R. Bystrup On

You're adding two java.lang.String's for which class Sun/Oracle have already supplied fitting .hashCode() and .equals() methods for you :-)

Note: It's not the collections that need the equals and hash methods - it's the objects you put into them!

If you were to add YourOwnClass objects to a JDK collection, you must override both these methods sensibly. Consider this, where YourOwnClass falls back to java.lang.Object's implementations of the methods in point:

class YourOwnClass
{
    String a;
    public YourOwnClass(String a) { this.a = a; }
}

public void testYourOwnClass() throws Exception
{
    Set<YourOwnClass> set = new HashSet<YourOwnClass>();

    System.out.println( set.add( new YourOwnClass( "b" ) ) );
    System.out.println( set.add( new YourOwnClass( "b" ) ) );
}

This will print

true

true

even though we could argue that the two YourOwnClass objects added should probably be considered identical from a semantic viewpoint.

Then, modify YourOwnClass as follows, and try again.

class YourOwnClass
{
    String a;
    public YourOwnClass(String a) { this.a = a; }

    @Override public int hashCode() { return a.hashCode(); }
    @Override public boolean equals(Object obj) { return a.equals( ((YourOwnClass)obj).a ); }
}

Voila - "true false" this time!

Cheers,

7
Braj On

Does Collection interface provide default equals() method?

Yes by default hashCode() method is used in equals() that is defined in Object class itself

For some classes such as String the equals() checks for characters for equality.

Check the source code of String.equals() method


If item is already added in Set then it returns false otherwise returns true as mentioned in Java Doc as well.

2
TheLostMind On

Ok.. To start off.

When hashset or linkedhashset is used. LinkedhashSet maintains order of inserted elements, HashSet doesnt.

I wonder how come the output is false The add() method returns true if the element is added (when the element is not already present in the set.So, in your case, first time around, "a" is not present in the set), so it returns true the first time around. the second time, "a" will already be present so, it will return false.

Next, by default, all objects have hashCode() and equals() implementations. You have to override them to change the default behaviour.

2
ha9u63a7 On

First thing first - I completely agree and +1 @TheLostMind answer above regarding LinkedHashset. Also, you probably are lacking the understanding of what .add() method is actually returning i.e. what does it check before returning you with a boolean result.

P.S. It's one of the standards in JavaBeans that you should override hashcode() and equals() to avoid erroneous results - see http://www.xyzws.com/javafaq/why-always-override-hashcode-if-overriding-equals/20

Remember that you are using HashSet and for HashSet the equals() and hashCode() methods are inherited from AbstractSet. AbstractSet is an abstract class and HashSet extends it and there is no requirement to implement any abstract methods. Because the equals() and hashCode() are implemented already, the result you see for the code below comes as true and false. I have separated them using scope {} operator to improve clarity.

public static void main (String[] args) throws java.lang.Exception
{

{   boolean[] b = new boolean[5]; 
    Set s = new HashSet(); 
    b[0]=s.add(new Integer(2)); 
    b[1]=s.add(new Integer(2));

    System.out.println("Using Hashset Integers b0 = "+b[0]+" and b1 = "+b[1]);
}

{   
    boolean[] b=new boolean[5]; 
    Set s=new HashSet(); 
    b[0]=s.add(2); 
    b[1]=s.add(2);
    System.out.println("Using Hashset int b0 = "+b[0]+" and b1 = "+b[1]);
}   


}

I believe for int and Integer hashCode() and equals() are alrady sorted out by Java. You don't need to worry about that. I implemented a dataserver using Spring Framework where I needed my own entity class and to make sure that I could save my Entity bean objects into a HashMap I had to override equals() and hashCode() in my Entity definition class. If you use Eclipse, you can use autogenerator to give you a skeleton of hashCode() and equals() which then can be edited to suit your needs.