更新:答案实际上在文档中:
Note: Great care must be exercised if mutable objects are used as set
elements. The behavior of a set is not specified if the value of an
object is changed in a manner that affects equals comparisons while
the object is an element in the set.
案件结案,谢谢大家!
编辑:关于散列集中重复项的引用主题确实有相同的观点,但是它没有回答我的问题:为什么文档没有说任何关于集合只能用于处理不可变对象?
edit2:我明白会发生什么.该组当然无法知道实体的哈希码何时在添加后发生变化.但问题是,文档应该清楚地说明set只能与不可变对象一起正常工作.
我已经用Java工作了5年多了,不要笑,但只是现在我才意识到套装的一些东西.我以为我理解了一套是什么,即文档说的是什么:
A collection that contains no duplicate elements. More formally, sets
* contain no pair of elementse1
ande2
such that *e1.equals(e2)
, and at most one null element.
但是,这完全不正确?!看这里:
public static void main(String[] args) {
Set<Entity> entitySet = new HashSet<>();
Entity e1 = new Entity("One");
Entity e2 = new Entity("Two");
entitySet.add(e1);
entitySet.add(e2);
e2.name = "One"; // !
System.out.println("Objects equal:" + e1.equals(e2));
Iterator<Entity> iterator = entitySet.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
static class Entity {
String name;
Entity(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Entity)) {
return false;
}
return name.equals(((Entity) obj).name);
}
@Override
public int hashCode() {
return name.hashCode();
}
@Override
public String toString() {
return "Entity[name=" + name + "]";
}
输出:
Objects equal:true
Entity[name=One]
Entity[name=One]
所以,我猜关于不包含重复项的集合的事情只有在我们处理不可变条目时才是真的吗?但为什么文件没有说什么呢?我从来没有真正意识到这一点.当然,问题在于,entites可能包含任何不属于等式定义的其他字段;他们在这些领域可能会有所不同.我在考虑这样的事情:
public static void main(String[] args) {
Set<Entity> entitySet = new HashSet<>();
Entity e1 = new Entity("Public", true);
Entity e2 = new Entity("Secret", false);
entitySet.add(e1);
entitySet.add(e2);
e2.name = "Public";
Iterator<Entity> iterator = entitySet.iterator();
// print only public entity (e1)
while (iterator.hasNext()) {
Entity e = iterator.next();
if (e.equals(e1)) {
System.out.println(e);
}
}
}
static class Entity {
String name;
boolean mayBeDisplayedToUser;
Entity(String name, boolean mayBeDisplayedToUser) {
this.name = name;
this.mayBeDisplayedToUser = mayBeDisplayedToUser;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Entity)) {
return false;
}
return name.equals(((Entity) obj).name);
}
@Override
public int hashCode() {
return name.hashCode();
}
@Override
public String toString() {
return "Entity[name=" + name + ", may be displayed:" + mayBeDisplayedToUser + "]";
}
}
输出:
Entity[name=Public, may be displayed:false] Entity[name=Public, may be
displayed:true]
所以..我现在很困惑.我是唯一一个不知道这一点的人吗?
解决方法:
您将这些项添加到HashSet中,因为它们是唯一的,然后在事后变更项.包含HashSet不知道您通过更改obj.name来破坏集合约.