I've got a class, "Accumulator", that implements the Comparable compareTo method, and I'm trying to put these objects into a HashSet.
When I add() to the HashSet, I don't see any activity in my compareTo method in the debugger, regardless of where I set my breakpoints. Additionally, when I'm done with the add()s, I see several duplicates within the Set.
What am I screwing up, here; why is it not Comparing, and therefore, allowing the dupes?
Thanks,
IVR Avenger
What am I screwing up, here?
HashSet is based on hashCode()
, not on compareTo()
. You may be confusing it with TreeSet
. In both cases, be sure to also implement equals()
in a manner that is consistent with the other method.
You need to correctly implement hashCode()
and equals()
.
You must override hashCode
and return a number based on the values in your class such that any two equal objects have the same hashcode.
HashSet uses the hashCode()
and equals()
methods to prevent duplicates from being added. First, it gets the hash code of the object you want to add. Then, it finds the corresponding bucket for that hash code and iterates through each object in that bucket, using the equals()
method to see if any identical objects already exist in the set.
Your debugger is not breaking on compareTo()
because it is never used with HashSet
!
The rules are:
If two objects are equal, then their hash codes
must be equal.
But if two objects' hash codes
are equal, then this doesn't mean
the objects are equal! It could be
that the two objects just happen to have the same hash.
When hashCode return different values for 2 objects, then equal is not used. Btw, compareTo has nothing to do with hashing collections :) but sorted collections
Your objects are Comparable
, and probably you've implemented equals()
too, but HashSets
deal with object hashes, and odds are you haven't implemented hashCode()
(or your implementation of hashCode()
doesn't return the same hash for two objects that are (a.equals(b) == true)
.
One thing which people tends to ignore which result in a huge mistake.
While defining equals method always take the parameter as object class and then conver the object to your desired class.
For eg
public bolean equals(Object aSong){
if(!(aSoneg instanceof Song)){
return false;
}
Song s=(Song) aSong;
return getTitle().equals(s.getTitle());
}
If u pass write Song aSong instead of Object aSong your equals method will never get called.
Hope this helps
HashSet uses hashCode and equals. TreeSet uses the Comparable interface. Note: if you decide to override either hashcode or equals, you should always override the other.
When ever you create an object of class Accumulator it takes new space in JVM and returns unique hashCode every time you add an object in hashSet. It does not depends upon the value of the object because you have not overridden hashCode() method hence it will call Object class hashCode() method which will return unique hashCode with every object created in your program.
Solution:
Override hashCode() and equals() method and apply your logic depending upon the properties of your class. Be sure to read equals and hashcode contract
http://www.ibm.com/developerworks/java/library/j-jtp05273/index.html