简体   繁体   中英

HashSet with Custom Type

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

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

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM