考虑以下compareTo方法,实现Comparable<T>
接口。:
@Override
public int compareTo(MyObject o)
{
if (o.value.equals(value)
return 0;
return 1;
}
显然,程序员将compareTo实现为equals()。显然是个错误。我希望这会导致Collections.sort()崩溃,但事实并非如此。相反,它只会给出一个任意结果:排序结果取决于初始排序。
public class MyObject implements Comparable<MyObject>
{
public static void main(String[] args)
{
List<MyObject> objects =
Arrays.asList(new MyObject[] {
new MyObject(1), new MyObject(2), new MyObject(3)
});
Collections.sort(objects);
System.out.println(objects);
List<MyObject> objects2 =
Arrays.asList(new MyObject[] {
new MyObject(3), new MyObject(1), new MyObject(2)
});
Collections.sort(objects2);
System.out.println(objects2);
}
public int value;
public MyObject(int value)
{
this.value = value;
}
@Override
public int compareTo(MyObject o)
{
if (value == o.value)
return 0;
return 1;
}
public String toString()
{
return "" + value;
}
}
结果:
[3, 2, 1]
[2, 1, 3]
我们能否为compareTo的这种奇怪实现提出一个用例,或者它总是无效的。如果是后者,它应该抛出异常,还是甚至不能编译?
答案 0 :(得分:5)
没有理由让它崩溃或抛出异常。
当您实施该方法时,您需要履行合同,但如果您不这样做,则只是意味着您将从依赖它的任何内容中获得任意结果。没有什么能够检查你的实现的正确性,因为这只会减慢一切。
排序算法的效率是根据它进行的比较次数来定义的。这意味着它不会仅仅为了检查您的实现是否一致而添加额外的比较,只需要HashMap
将两次调用.hashcode()
只是为了检查它两次都是一样的结果。
如果发生在排序过程中发现问题,那么它可能会抛出异常;但不要依赖它。
答案 1 :(得分:1)
违反Comparable
或Comparator
的合同并不一定会导致例外。 sort
方法不会花费额外的努力来检测这种情况。因此,它可能会导致顺序不一致,结果明显正确或抛出异常。
实际行为取决于输入数据和当前实现。例如。 Java 7在其TimSort
实现中引入了sort
,与早期Java版本的实现相比,它更可能抛出不一致的Comparable
或Comparator
实现的异常。这可能会发现在使用以前的Java版本时仍然未检测到的错误,但是,这不是首先帮助调试的功能,它只是更复杂的优化的副作用。
请注意,对于像您的问题中的简单情况,编译器或代码审计工具并非完全不可能检测到比较方法的不对称行为。但是,据我所知,没有编译器自动执行此类检查。如果您想要安全起见,则应始终对实现Comparable
或Comparator
的类实施单元测试。
答案 2 :(得分:0)
根据文档,Collections.sort()使用merge sort的变体,它将列表分成多个子列表,然后重复合并这些列表;排序部分是在合并这些列表的过程中完成的;如果你的比较方法是任意的,那么将会以任意顺序进行合并。
答案 3 :(得分:-1)
因此,每个元素都比所有其他元素都大。
根据您想要表示的数学组或顺序,它可能是有效的案例,因此没有理由抛出任何错误。但是,您显示的示例并不代表数字的自然顺序,正如您通过标准所知的那样。
所呈现的订单并非全部。
== EDIT ==
感谢您的评论,规范不允许使用compareTo方法来实现非全部或非反对称订单。