当前位置: 首页 > 知识库问答 >
问题:

为什么SortedSet的equals方法必须打破Set契约?

宋铭
2023-03-14

SortedSet

我很难理解为什么有必要实施SortedSetequals方法,从而打破集的总合同,如下所示:

请注意,如果排序集要正确实现set接口,则排序集维护的排序(无论是否提供显式比较器)必须与equals一致。(参见Comparable接口或Comparator接口,了解与equals一致的精确定义。)这是因为Set接口是根据equals操作定义的,但排序集使用其compareTo(或compare)方法执行所有元素比较,因此从排序集的角度来看,此方法认为相等的两个元素是相等的。即使排序集的顺序与equals不一致,排序集的行为也是定义良好的;它只是没有遵守集合接口的总合同。

从浏览源代码来看,SortedSet目前的工作方式如下。给定两个SortedSet实例aba.equals(b)将:

  • 委托比较AbstractSet#equals(Object o)
    • 检查无效,铸造问题,并确保集合大小相等
    • c中的所有元素e上循环并调用this。包含(e)
    • 这将检查TreeMap#getEntry(key)是否为null
    final Entry<K,V> getEntry(Object key) {
        // Offload comparator-based version for sake of performance
        if (comparator != null)
            return getEntryUsingComparator(key);
        if (key == null)
            throw new NullPointerException();
        @SuppressWarnings("unchecked")
            Comparable<? super K> k = (Comparable<? super K>) key;
        Entry<K,V> p = root;
        while (p != null) {
            int cmp = k.compareTo(p.key);
            if (cmp < 0)
                p = p.left;
            else if (cmp > 0)
                p = p.right;
            else
                return p;
        }
        return null;
    }
    

    要确定两个SortedSet实例ab是否相等,我个人认为:

    1. 在当前实现中执行相同的初始检查,例如大小比较
    2. 在seta
    3. 的第一个元素上启动光标
    4. 在setb
    5. 的第一个元素上启动光标
    6. 比较元素与自己的equals方法
    7. 将两个游标移动到下一个元素,然后转到步骤4,直到元素耗尽。

    由于排序顺序是由比较器compareTo方法保证的,因此我看不出有什么理由不起作用。

    • 我的上述方法有问题吗

共有1个答案

娄飞鸾
2023-03-14

您只考虑sortedSetA。等于(sortedSetB)

sortedSetA。如果元素相同,即使遍历顺序不同,equals(hashSetA)也应返回true。

设置::e质量

如果指定的对象也是一个集合,两个集合的大小相同,并且指定集合的每个成员都包含在此集合中,则返回true

这就是为什么执行遵循一般情况。

您的实现不但没有遵守契约,还破坏了Set的契约,因为两个具有相同元素并以不同方式排序的集合将被视为不相等。

 类似资料:
  • 本文向大家介绍hashCode 与 equals ?为什么重写equals时必须重写hashCode方法?相关面试题,主要包含被问及hashCode 与 equals ?为什么重写equals时必须重写hashCode方法?时的应答技巧和注意事项,需要的朋友参考一下 面试官可能会问你:“你重写过 hashcode 和 equals 么,为什么重写equals时必须重写hashCode方法?” ha

  • 本文向大家介绍为什么在重写 equals方法的同时必须重写 hashcode方法,包括了为什么在重写 equals方法的同时必须重写 hashcode方法的使用技巧和注意事项,需要的朋友参考一下 我们都知道Java语言是完全面向对象的,在java中,所有的对象都是继承于Object类。 其 equals 方法比较的是两个对象的引用指向的地址,hashcode 是一个本地方法,返回的是对象地址值。O

  • 问题内容: 无论是Javadoc还是代码本身,Comparator接口都定义了: 但这没有编译任何概率: 但这确实是: 接口不允许用户重写方法的方法是什么? 问题答案: 首先,JavaDocs清楚地解释了您应该实现此方法: 此外,仅当指定对象也是一个比较器并且施加与该比较器相同的顺序时,此方法才能返回true。因此,意味着对于每个对象引用和。 但后来: 请注意,始终不要覆盖即可。 即使它是接口的一

  • 问题内容: 如果我重写一个类两种方法,它必须确保,如果那么也必须是真实的。 有人可以告诉我一个简单的示例,如果违反了该示例,将会引起问题吗?我认为这与您使用该类作为Hashmap的键类型有关吗? 问题答案: 当然: 与: 从技术上讲应该是正确的,因为在两种情况下m == 3。 通常,HashMap的工作方式如下:它具有可变数量的通常称为“存储桶”的数量。存储桶的数量可以随时间变化(随着条目的添加和

  • 在上面的代码中,为什么在< code>main()中强制提到< code>String args[]以及为什么我们得到< code > "[ljava . lang . String;@174e5edb"作为输出?

  • 问题内容: 我开始学习Go,但对以下内容有所了解: 失败的原因是: 考虑到实现的事实,我不明白为什么Go不接受签名。有人可以帮忙解释吗? 问题答案: 我认为您对界面的理解不够充分。Interface {}本身就是一种类型。它由两部分组成:基础类型和基础值。 Golang没有重载。Golang类型系统按名称匹配,并且要求类型一致 因此,当您定义将接口类型作为参数的函数时: 这与采用int类型的函数不