具有自定义类型的HashSet

时间:2014-08-24 06:31:42

标签: java hash set

我想知道为什么HashSet与自定义类型对象的行为很奇怪。在下面的String代码中,它总是会给出不同的结果,但对于人类相同类型的结果进行排序。我的

有什么问题
equals or hashCode or compareTo ?

请让我理解。谢谢你。

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;
    }
   }

代码:

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());
}

输出

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

3 个答案:

答案 0 :(得分:2)

  

总是会给出不同的结果,但对于人类相同类型的结果进行排序。我的

有什么问题

HashSet中的订单无法保证,如果您希望按照compareTo()的顺序进行维护,请使用TreeSet

答案 1 :(得分:2)

没有破碎。您获取排序结果的原因是因为您的自定义hashCode方法没有非常随机的hash distribution

HashSet类由一系列&#34;桶&#34;支持。当您向HashSet添加内容时,它会使用您的hashCode方法来确定要使用的存储分区。我认为它的工作原理如下:

bucketIndex = object.hashCode() % arrayLength;

由于您的hashCode()只是ID,因此您最终会按顺序将人类添加到存储桶中。如果你为了使它更随机地分布你的哈希函数,那么你应该在哈希集中获得更随机的排序。

答案 2 :(得分:2)

字符串的哈希码方法比简单返回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]

这就是为什么订单可能会在字符串上发生奇怪的原因。

现在为什么在自定义对象的情况下对它进行排序是因为hashset的内部工作原因。需要记住的重要一点是:“它不能保证集合的迭代顺序;特别是,它不能保证订单随时间保持不变。”但是它仍然需要以某种方式对它们进行排序以便能够快速找到它们。此顺序基于哈希码结果模(%)哈希集的实际容量。

你的3方法可能适合你的需要,但你应该知道如果两个对象是equals()并且你在HashSet中都添加它们,那么第二个将覆盖第一个。如果相等应仅在id或更多字段上,则可以选择此选项。