Reputation: 10953
I would like to know why HashSet behaves strangely with custome type objects.In below code for String always it gives different results but for Human same type of result which is sorted.Is there something wrong in my
equals or hashCode or compareTo ?
Please hlep me to understand.Thanks in Advance.
Bean :
public class Human implements Comparable<Human>
{
private int id;
private String name;
private int age;
// setters and getters
public Human(int id,String name,int age)
{
this.id = id;
this.name = name;
this.age = age;
}
@Override
public int hashCode()
{
return id;
}
@Override
public boolean equals(Object object)
{
if(object != null && object instanceof Human)
{
if(this.id == ((Human)object).getId())
{
return true;
}
}
return false;
}
@Override
public String toString()
{
String s = "id:"+this.id+":name:"+this.name+":age:"+age;
return s;
}
@Override
public int compareTo(Human human) {
if(this.id > human.getId())
return 1;
else if(this.id < human.getId())
return -1;
else
return 0;
}
}
Code :
System.out.println("HashSet");
Set<String> set1 = new HashSet<String>();
set1.add("3");
set1.add("1");
set1.add("2");
set1.add("4");
Iterator<String> iter1 = set1.iterator();
while(iter1.hasNext())
{
System.out.println(iter1.next());
}
System.out.println("HashSet with Custom Objects");
Set<Human> set11 = new HashSet<Human>();
set11.add(new Human(1, "joe", 26));
set11.add(new Human(3, "leo", 109));
set11.add(new Human(2, "king", 18));
set11.add(new Human(0, "vkgentle", 10));
Iterator<Human> iter11 = set11.iterator();
while(iter11.hasNext())
{
System.out.println(iter11.next().toString());
}
Output :
HashSet
3
2
1
4
HashSet with Custom Objects
id:0:name:vkgentle:age:10
id:1:name:joe:age:26
id:2:name:king:age:18
id:3:name:leo:age:109
Upvotes: 0
Views: 2466
Reputation: 929
The hashcode method of a string is a bit more complex that your simple return id;
http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#hashCode%28%29
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
So that is why the order might seam strange on a string.
Now why is it ordered in the case of your custom object is because of the inner working of hashset. The important thing to remember is that : "It makes no guarantees as to the iteration order of the set; in particular, it does not guarantee that the order will remain constant over time." But yet it still has to order them in some way to be able to find them fast. This order is based on the hashcode result modulo (%) the actual capacity of the hashset.
Your 3 method might be right for your need, but you should know that if two object are equals() and you add them both in your HashSet the second one will overwrite the first one. This is the your choice if the equality should be only on the id or on more field.
Upvotes: 2
Reputation: 33029
There's nothing broken. The reason you're getting sorted results is because your custom hashCode method doesn't have a very random hash distribution.
The HashSet
class is backed by an array of "buckets". When you add something to the HashSet
it uses your hashCode
method to figure out which bucket to use. I think it works something like this:
bucketIndex = object.hashCode() % arrayLength;
Since your hashCode()
is just the ID, you end up with the Humans added to the buckets in order. If you mess with your hash function a bit in order to make it more randomly-distributed then you should get a more random ordering in the HashSet.
Upvotes: 3
Reputation: 240928
always it gives different results but for Human same type of result which is sorted.Is there something wrong in my
order in HashSet
is not guaranteed, if you want ordered to be maintained respecting your compareTo()
then use TreeSet
Upvotes: 2