java 在Comparable类中实现compareTo时,特定的有符号整数是否重要< Type>?

qojgxg4l  于 2023-01-11  发布在  Java
关注(0)|答案(3)|浏览(106)

在实现compareTo()时,是否需要考虑“差异”的程度?
例如,如果我有3个对象,C1、C2和C3,使得C1〈C2〈C3。
C1.compareTo(C2)是否应返回一个小于C2.compareTo(C3)的整数?
Comparable接口的文档似乎没有指定这样或那样的方式,所以我猜程度并不重要,但如果知道返回特定数字是否有什么好处(例如,提高TreeSet排序速度或其他),那就太好了。
http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Comparable.html#compareTo(T)

v1uwarro

v1uwarro1#

这个问题很有趣,但并不重要,根据Comparable<T>Comparator<T>规范,int的大小没有意义,只有符号。可以想象,一些排序算法可以额外指定它们可以从大小中获取“提示”,但我不确定这对于基于比较的排序是否实用,因为我们实际上只需要知道a < ba == ba > b(这实际上是ComparableComparator的OOP抽象)。
现在需要说明的是,这里可能有一个隐藏的意图,就是用减法这个成语来比较数值,也就是说,大概是这样的:

public int compare(T t1, T t2) {
    return t1.intField - t2.intField;
}

请注意,这种比较方法 * 可能 * 被破坏,因为当两个数之差大于Integer.MAX_VALUE时,可能会溢出。实际上,这是Java Puzzlers中涉及的谜题之一。
为了证明这一点,请看下面的片段(摘自本书):

int x = -2000000000;
int z = 2000000000;
System.out.println(x - z); // prints a positive number due to overflow

显然x < z是正数,但x - z是正数,使用减法时要小心:执行显式比较并使用return -101总是安全得多。

hec6srdp

hec6srdp2#

不,唯一的区别是负数0和正数之间的区别。度数无关紧要。

7qhs6swi

7qhs6swi3#

我发现Comparator.compare(left, right)返回的大小对TreeSet来说很重要。我认为大小在某种程度上给了TreeSet一个提示,允许在某些情况下跳过比较。我没有花时间完全理解实现细节,但我必须修复下面的比较器。

@AllArgsConstructor
public class ObjectDependencyComparator implements Comparator<ObjectId> {
    private final Map<ObjectId, Set<ObjectId>> dependencies;

    @Override
    public int compare(ObjectId left, ObjectId right) {
        int nameCompare = left.toString().compareTo(right.toString());
        if (nameCompare == 0) {
            return 0;
        }
        boolean leftDependsOnRight = dependsOn(left, right);
        boolean rightDependsOnLeft = dependsOn(right, left);
        if (leftDependsOnRight == rightDependsOnLeft) {
            return nameCompare;
        } else {
            return leftDependsOnRight ? 1 : -1;
        }
    }

    /**
     * @return true if left (or one of its dependencies) depends on right
     */
    private boolean dependsOn(ObjectId left, ObjectId right) {
       ...
    }
}

上面的比较器在逻辑上是正确的(即正确地返回负或正),但是当我把对象放入TreeSet时,排序并不像预期的那样。问题是String.compareTo(...)并不总是返回-1、0或1(例如,它可能返回-7或5)。我必须如下修复比较器

if (leftDependsOnRight == rightDependsOnLeft) {
        return nameCompare > 0 ? 1 : -1;
    } else {
        return leftDependsOnRight ? 1 : -1;
    }

通过以上修复,我的比较器只能返回-1、0或1,这修复了TreeSet排序问题。

相关问题