Java如何仅通过实现Comparable接口完成自定义对象排序?
为什么自定义类需要实现Comparable接口才能调用Collections.sort()
Collections.sort()默认使用集合元素的自然排序规则完成排序。对于String、Integer这类JDK内置类,Java已经内置了默认的排序规则(比如字符串按字典序、整数按数值大小排序),但自定义类的大小判定逻辑是业务自定义的——比如你的Point类,你可能想按横坐标排序、按纵坐标排序、按到原点的距离排序,Java无法预先知道你需要的判定规则。Comparable是Java官方定义的「支持自然排序」的约定接口,只有实现了这个接口的类,Collections.sort()才能识别到它的比较规则,如果你没有实现该接口就调用排序方法,运行时会抛出ClassCastException异常。
如果你不想修改原类代码实现Comparable,也可以使用重载的Collections.sort(List<T> list, Comparator<? super T> c)方法,直接传入自定义比较器指定排序规则,不需要改动Point类的代码。
compareTo返回值的排序逻辑
首先纠正一个小误区:compareTo不是只能返回-1、0、1,只要返回负整数、0、正整数三类结果都符合要求,只是大家习惯用-1、0、1来简化返回值而已。
排序算法的核心逻辑都是两两比较元素、根据比较结果调整位置,compareTo的返回值就是给排序算法提供两两比较的判定规则:假设我们调用a.compareTo(b),返回值的含义如下:
- 返回负整数:判定
a的顺序在b之前(a小于b) - 返回0:判定
a和b的排序优先级相等,不需要交换位置 - 返回正整数:判定
a的顺序在b之后(a大于b)
比如你的Point类要按存储的数值升序排序,就可以按如下方式实现:
public class Point implements Comparable<Point> { private int value; public Point(int value) { this.value = value; } @Override public int compareTo(Point other) { // 直接使用Integer的比较方法,避免手动写减法出现数值溢出问题 return Integer.compare(this.value, other.value); } }
举个实际比较的例子:当排序算法比较new Point(4)和new Point(2)时,会调用point4.compareTo(point2),得到正整数返回值,就会把point2调整到point4前面,最终完成整个集合的升序排序。
内容的提问来源于stack exchange,提问作者Nam Trường

