Java 错误:“比较方法违反了其总协定!

2022-09-04 21:28:04

我有这个代码:

package org.optimization.geneticAlgorithm;
import org.optimization.geneticAlgorithm.selection.Pair;

public abstract class Chromosome implements Comparable<Chromosome> {
    public abstract double fitness();
    public abstract Pair<Chromosome> crossover(Chromosome parent);
    public abstract void mutation();
    public int compareTo(Chromosome o) {
        int rv = 0;
        if (this.fitness() > o.fitness()) {
            rv = -1;
        } else if (this.fitness() < o.fitness()) {
            rv = 1;
        }
        return rv;
    }
}

每次我运行此代码时,我都会收到此错误:

Exception in thread "main" java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.ComparableTimSort.mergeHi(ComparableTimSort.java:835)
at java.util.ComparableTimSort.mergeAt(ComparableTimSort.java:453)
at java.util.ComparableTimSort.mergeCollapse(ComparableTimSort.java:376)
at java.util.ComparableTimSort.sort(ComparableTimSort.java:182)
at java.util.ComparableTimSort.sort(ComparableTimSort.java:146)
at java.util.Arrays.sort(Arrays.java:472)
at java.util.Collections.sort(Collections.java:155)
at org.optimization.geneticAlgorithm.GeneticAlgorithm.nextGeneration(GeneticAlgorithm.java:74)
at org.optimization.geneticAlgorithm.GeneticAlgorithm.execute(GeneticAlgorithm.java:40)
at test.newData.InferenceModel.main(InferenceModel.java:134)

我使用OpenJDK7u3,当对象相等时返回0。有人可以向我解释这个错误吗?


答案 1

如果您有任何NaN值,您可能会遇到这种情况:

例如:

public class Test
{
    public static void main(String[] args) {
        double a = Double.NaN;
        double b = Double.NaN;
        double c = 5;

        System.out.println(a < b);
        System.out.println(a > b);
        System.out.println(b < c);
        System.out.println(c < b);
    }
}

所有这些打印.因此,您可能最终会遇到两个非 NaN 值都被视为与 NaN“相等”,但一个大于另一个的情况。基本上,您应该弄清楚如何处理NaN值。当然,还要检查这是否真的是问题所在...你真的想要NaN值来健身吗?false


答案 2

最有可能的是,您的健身功能被破坏了,有两种方式之一:

  1. 在同一对象上调用时,它并不总是返回相同的值。
  2. 它可以返回 NaNs。在 NaNs 存在的情况下,您不是可传递的,正如 Jon Skeet 所解释的那样。compareTo()

您可以使用以下命令重写比较函数:Double.compare()

public int compareTo(Chromosome o) {
    return Double.compare(o.fitness(), this.fitness());
}

这需要更少的代码,并处理角落情况(NaNs,负零等)。当然,这些角落案件是否应该首先出现,由您来决定和解决。


推荐