2011-08-11 92 views
10

关于Java HashSet的新手问题理解包含Java HashSet的方法

Set<User> s = new HashSet<User>(); 
User u = new User(); 
u.setName("name1"); 
s.add(u); 
u.setName("name3"); 
System.out.println(s.contains(u)); 

有人可以解释为什么这代码输出错误的?而且这个代码甚至不会调用User的equals方法。但根据HashSet和HashMap的来源,它必须调用它。方法等于用户简单地调用用户名称上的等于。方法hashCode返回用户名的hashCode

+0

你执行'User.equals()'方法? –

+0

引用Jon Skeet“哈希集合中的对象应该是不可变的,或者你需要在哈希集合(或散列表)中使用哈希集合后,不要改变它们。” - http://stackoverflow.com/questions/4718009/mutable-objects-and-hashcode – Qwerky

回答

13

如果哈希码的方法是基于name的字段,然后在添加对象后再改变它,那么第二个contains检查将使用新的哈希值,并且不会查找你正在寻找的对象。这是因为HashSet是首次使用哈希码进行搜索,所以如果搜索失败,他们不会打扰equals

这会工作的唯一方法是,如果你有没有覆盖equals(所以使用了默认引用相等)你很幸运,这两个对象的哈希码都是平等的。但这是一个不太可能发生的情况,你不应该依赖它。

一般来说,你应该从来没有更新一个对象,你已经添加到HashSet后,如果该更改也将更改其哈希码。

+0

所以它是你在哈希集中添加的副本?否则,我会认为nameset中的对象将具有name3以及 – Ced

9

由于您的新User具有不同的哈希码,因此HashSet知道它不相同。

HashSets根据它们的哈希码存储它们的项目。
HashSet中只会叫equals如果找到具有相同散列码的项目,以确保这两个项目实际上是相等的(而不是一个哈希碰撞)

+1

实际上,只有在hashCode相等时才调用equals。这意味着如果我更新用户,它会更改它的hashCode,包含与其hashCodes相关联的Entry的嵌套数组将不会更新。因此迭代这个数组不会返回具有相同hashCode的条目。如果hashCode总是返回0,应该工作) – user12384512

+3

正确。一般来说,在HashSet中放置可变对象是一个坏主意。如果你使'hashCode()'返回'0',你将失去HashSet的所有性能好处,并且最终会得到你可能获得的最慢集合。 – SLaks

+0

我知道,这只是一个例子 – user12384512