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

为什么我的比较方法违反了它的总契约?

姜经武
2023-03-14
public static Comparator<Container> DEPARTURE = new Comparator<Container>() {
    @Override
    public int compare(Container container1, Container container2) {
        if (container1.departure.time.isBefore(container2.departure.time))
            return -1;
        else if (container1.departure.time.equals(container2.departure.time) && 
                 container1.departure.maxDuration == container2.departure.maxDuration && 
                 container1.departure.transportCompany.equals(container2.departure.transportCompany) && 
                 container1.departure.transportType == container2.departure.transportType)
            return 0;
        else
            return +1;
    }
};

偏离变量只是包含以下字段的对象的一个实例:

    public DateTime time;
    public int maxDuration;
    public TransportType transportType;
    public String transportCompany;

附言时间对象是来自 Joda-Time 库的 DateTime 实例,TransportType 是包含常量火车、海船、驳船和卡车的枚举。

编辑:

好的,所以我将比较器编辑为以下内容:

    public static Comparator<Container> DEPARTURE = new Comparator<Container>() {
        @Override
        public int compare(Container container1, Container container2) {
            if (container1.departure.time.isBefore(container2.departure.time))
                return -1;
            else if (container1.departure.time.isBefore(container2.departure.time))
                return +1;
            else {
                if (container1.departure.maxDuration == container2.departure.maxDuration && container1.departure.transportType == container2.departure.transportType && container1.departure.transportCompany.equals(container2.departure.transportCompany))
                    return 0;
                else
                    return +1;
            }
        }
    };

但这显然违反了一般契约。我如何让它按时间排序,然后根据它们的其他属性对那些具有相等时间的对象进行排序,只关心它们是否相等?希望这有意义…

编辑:解决方案

谢谢大家回答我的问题!在研究了你的评论后,我想出了下面的解决方案,它似乎是有效的(尽管还没有经过彻底的测试):

我实际上将比较部分移到了离开他的班级,因为我也需要按到达进行比较。我决定简单地按所有属性(连续时间、最大持续时间、传输公司和运输类型)进行排序,我想出的解决方案是:

    public static Comparator<Container> ARRIVAL = new Comparator<Container>() {
        @Override
        public int compare(Container container1, Container container2) {
            return container1.arrival.compareTo(container2.arrival);
        }
    };

    public static Comparator<Container> DEPARTURE = new Comparator<Container>() {
        @Override
        public int compare(Container container1, Container container2) {
            return container1.departure.compareTo(container2.departure);
        }
    };

然后使用compareTo方法:

    @Override
    public int compareTo(LocationMovement lm) {
        if (this.time.isBefore(lm.time))
            return -1;
        else if (this.time.isAfter(lm.time))
            return +1;
        else {
            int c = this.maxDuration - lm.maxDuration;
            if (c != 0) return c;

            c = this.transportCompany.compareTo(lm.transportCompany);
            if (c != 0) return c;

            c = this.transportType.ordinal() - lm.transportType.ordinal();
            return c;
        }
    }

共有3个答案

汤枫涟
2023-03-14

请注意,如果两个容器< code>c1和< code>c2具有相同的< code > department . time ,但其他属性不同,则< code>compare(c1,c2)和< code>compare(c2,c1)都将返回< code> 1,即< code>c1

相反,您应该完全删除其他字段,或者在出发时间相等的情况下在嵌套或顺序 if-elses 中单独比较它们。

看看这个相关问题的答案,了解一种通过多个属性比较对象的干净方法。

车靖琪
2023-03-14

为了实现compare,您检查的所有项目都必须具有相互“较小”、“较大”或“相等”的概念,然后您必须决定检查它们的顺序,对第一个不相等的项目返回较小/较大。这样,您就满足了合同,即compare(a,b)必须是compare(b,a)的反面。如果您正在比较的所有部分都没有“较大”或“较小”的概念(例如,传输类型),那么要么您无法实现compare,要么您必须强制对它们进行任意(但可靠)的较大/较小解释。

这是一个概念性的例子。在这种情况下,我选择的顺序(任意)是:时间、持续时间、公司和类型。但是不同的顺序可能更合理。这只是一个例子。此外,您还没有说明< code>transportType的类型是什么,所以我假设它有一个< code>compareTo方法;显然,它可能不会,你可能需要调整。

public static Comparator<Container> DEPARTURE = new Comparator<Container>() {
    @Override
    public int compare(Container container1, Container container2) {
        int rv;

        // Times
        rv = container1.departure.time.compareTo(container2.departure.time);
        if (rv == 0) {
            // Duration
            if (container1.departure.maxDuration < container2.departure.maxDuration) {
                rv = -1;
            }
            else if (container1.departure.maxDuration > container2.departure.maxDuration) {
                rv = 1;
            }
            else {
                // Transport company
                rv = container1.departure.transportCompany.compareTo(container2.departure.transportCompany);
                if (rv == 0) {
                    // Transport type
                    rv = container1.departure.transportType.compareTo(container2.departure.transportType);
                }
            }
        }
        return rv;
    }
};
薛涛
2023-03-14

一般合同是

COMPARATOR.compare(a, b) = - COMPARATOR.compare(b, a)

在您的例子中,一方面返回-1的代码可能另一方面返回0。

 类似资料:
  • 有人能解释一下为什么我下面的比较器有时候会抛出上面的异常吗? 注意:myObject 中的 id 字段类型为 long。 解决方案: 基于@amit的回答

  • 我有时会得到一个 for 我可以始终如一地抛出此异常,实时数据运行足够长的时间,但我不确定如何解决问题的实际原因。 我的比较仪有什么问题?(具体来说,我违反了合同的哪一部分?)如何在不掩盖异常的情况下修复它? 我使用的是 Java 7,如果不进行重大重写就无法升级。 我可以通过将设置为来掩盖异常,但这不是一个理想的解决方案。 我尝试创建测试来随机生成数据并验证每个合同条件。我无法抛出异常。 我尝试

  • 我制作了一个带有jPanel和JLabel数组的调色板。起初它运行良好,但后来我从 JPanel 中取出了一些其他 jLabels,并添加了一些事件。现在我不断收到此错误: 我试图删除第一次收到此错误后所做的一切,但仍然不断收到它。当我将布局从 GridLayout 更改为其他任何内容时,错误消失了,但代码变得无用。所以我需要网格布局。当我将该 JPanel 中的所有内容移动到另一个 JPanel

  • 问题内容: 有人可以简单地向我解释一下,为什么此代码会引发异常,“比较方法违反了它的一般约定!”,我该如何解决? 问题答案: 你的比较器不是可传递的。 让是的父,并成为母公司。既然和,那一定是这样。但是,如果在和上调用比较器,它将返回零,即。这违反了合同,因此引发异常。 该库可以很好地检测到这一点并让你知道,而不是行为不规律。 满足传递性要求的一种方法是遍历整个链,而不仅仅是查看直接祖先。

  • 我在整理名单 排序代码: FinalSentence类标头: compareTo()实现: 这是例外: 对于一个小列表(少于 50 个元素),它可以工作。对于一个大型列表(它也应该与那些一起使用),它会引发此异常。列表的实例类型是 ArrayList,这并不重要。 我不知道如何深入了解这一点。列表已满,元素类型相同(那里没有多态性),但是对于大型列表,我得到了这个奇怪的例外。 有什么想法吗? 谢谢

  • 我有这个代码。getCreatedAt 是一个长整型,表示记录的时间戳。 当我使用足够的数据(列表中大约有 200 个项目)运行它时。我开始遇到这个异常 java.lang.IllegalArgumentException:比较方法违反了它的一般约定! 当然,当我编写此代码时,我意识到理论上它可以具有整数溢出,但感觉不太可能,因为时间戳将相隔几天或几周,而不是几十年。 我现在已经通过总是返回1、-