我想知道为什么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
答案 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或更多字段上,则可以选择此选项。