【问题标题】:Set can contain duplicates?集合可以包含重复项吗?
【发布时间】:2016-01-06 14:19:45
【问题描述】:

更新:答案实际上在文档中:

注意:如果使用可变对象作为集合,必须非常小心 元素。如果一个集合的值未指定,则集合的行为 对象以影响等于比较的方式更改,而 对象是集合中的一个元素。

案件结束,谢谢大家!

编辑:关于哈希集中重复项的引用主题确实具有相同的观点,但它没有回答我的问题:为什么文档没有说明一个集合只能保证与不可变对象一起使用?

edit2:我明白会发生什么。该集合当然无法知道实体的哈希码在添加后何时更改。但重点是 imo 文档应该清楚地说明 set 仅适用于不可变对象。

我已经使用 Java 超过 5 年了,别笑,但直到现在我才意识到关于 Sets 的一些事情。我以为我明白了什么是集合,即文档所说的:

不包含重复元素的集合。更正式地说,集合 * 不包含任何一对元素 e1e2 使得 * e1.equals(e2),并且最多包含一个空元素。

但是,这完全不是真的?!见这里:

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]

所以,我猜只有当我们处理不可变条目时,关于不包含重复项的集合才是正确的?但是为什么医生没有说什么?我从来没有真正意识到这一点。这样做的问题当然是实体可以包含任意数量的不属于相等定义的其他字段。他们在这些领域可能会有所不同。我正在考虑这样的事情:

 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,可能显示:false] Entity[name=Public,可能显示 显示:真]

所以.. 我现在很困惑。只有我不知道这一点吗?

【问题讨论】:

  • 我们确定 by equals 集合不会执行 '==' 指示两个变量指向同一个对象吗?这将允许您提出的案例。
  • 我不知道。他覆盖了equals和hashCode。我猜合同在这里的某个地方被打破了......
  • 我遵守hashcode和equals的约定。如果我的实体相等,那么它们具有相同的哈希码。我只是将这两种方法都委托给“名称”变量。因此,只要我们假设 String 类正确地实现了这些方法,那么它应该可以在 imo 中工作。
  • 哈希码仅在您将项目添加到 HashSet 时创建和测试。您对对象所做的后续更改不会导致重新计算哈希码。

标签: java set duplicates equals


【解决方案1】:

您正在将项目添加到 HashSet,而它们是唯一的,然后在事后改变这些项目。包含HashSet 不知道您通过更改obj.name 违反了设定的合同。

【讨论】:

  • 啊,你是对的。此处描述了这种情况以供进一步阅读。 stackoverflow.com/questions/13114043/…
  • 我理解这种行为。我想我的问题错了。我的问题是为什么文档中没有说明可变元素的这个问题,如果人们知道这一点
  • 啊,谢谢@Locke。所以实际上它在文档中有所描述。所以我想我从来没有正确地阅读过……好的,谢谢,案例已结束:)
  • 嘿@user3237736,您应该接受现有答案或编写自己的答案并在问题解决后接受。
猜你喜欢
  • 2012-01-22
  • 1970-01-01
  • 2012-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-17
  • 1970-01-01
  • 2013-05-27
相关资源
最近更新 更多