理解包含Java HashSet的方法
Posted
技术标签:
【中文标题】理解包含Java HashSet的方法【英文标题】:Understanding contains method of Java HashSet 【发布时间】:2011-10-24 23:44:44 【问题描述】:关于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));
有人可以解释为什么这段代码输出 false 吗?此外,这段代码甚至没有调用 User 的 equals 方法。但是根据 HashSet 和 HashMap 的来源,它必须调用它。 User 的方法 equals 只是在用户名上调用 equals。方法hashCode返回用户名的hashCode
【问题讨论】:
引用 Jon Skeet “hashsets 中的对象应该是不可变的,或者你需要遵守纪律,在它们被用于 hashset(或 hashmap)之后不要更改它们。” - ***.com/questions/4718009/… 【参考方案1】:由于您的新 User
具有不同的哈希码,HashSet 知道它不相等。
HashSet 根据它们的哈希码存储它们的项目。
HashSet 只会在找到具有相同哈希码的项目时调用equals
,以确保这两个项目实际上相等(而不是哈希冲突)
【讨论】:
确实,只有当 hashCode 相等时它才会调用 equals。这意味着,如果我更新用户,将其更改为 hashCode,则包含与其 hashCode 关联的 Entry 的嵌套数组将不会被更新。所以遍历这个数组不会返回具有相同 hashCode 的条目。如果 hashCode 总是返回 0 应该可以工作) 正确。通常,将可变对象放入 HashSet 是一个坏主意。如果你让hashCode()
返回0
,你将失去 HashSet 的所有性能优势,你最终会得到你可能得到的最慢的集合。
我知道,这只是一个例子
我相信这应该是公认的答案。值得注意的是,HashSet.contains()
的 javadoc 没有说明仅在检查哈希码后才应用等号。【参考方案2】:
如果哈希码方法是基于name
字段的,而你在添加对象后更改它,那么第二次contains
检查将使用新的哈希值,并且不会找到你的对象寻找。这是因为HashSet
s 首先通过哈希码进行搜索,所以如果搜索失败,他们就不会打扰调用equals
。
唯一可行的方法是如果你没有覆盖equals
(因此使用了默认的引用相等)并且你很幸运并且哈希两个对象的代码是相等的。但这是一个真的不太可能发生的情况,你不应该依赖它。
一般来说,您应该从不在将对象添加到HashSet
后更新它,如果该更改也会更改其哈希码。
【讨论】:
所以它是你在哈希集中添加的副本?否则我认为 nameset 中的对象也会有 name3以上是关于理解包含Java HashSet的方法的主要内容,如果未能解决你的问题,请参考以下文章