理解包含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检查将使用新的哈希值,并且不会找到你的对象寻找。这是因为HashSets 首先通过哈希码进行搜索,所以如果搜索失败,他们就不会打扰调用equals

唯一可行的方法是如果你没有覆盖equals(因此使用了默认的引用相等)并且你很幸运并且哈希两个对象的代码是相等的。但这是一个真的不太可能发生的情况,你不应该依赖它。

一般来说,您应该从不在将对象添加到HashSet 后更新它,如果该更改也会更改其哈希码。

【讨论】:

所以它是你在哈希集中添加的副本?否则我认为 nameset 中的对象也会有 name3

以上是关于理解包含Java HashSet的方法的主要内容,如果未能解决你的问题,请参考以下文章

HashSet理解java集合

java list去重

HashSet理解add方法(jdk1.7及以前)是如何插值的

由浅入深理解java集合——集合 Set

Java集合之HashSet

HashSet理解怎么做到值不重复