必须实现Comparable接口时:类需支持Arrays.sort()、Collections.sort()或作为TreeSet/TreeMap的key;一个类仅能有一种自然顺序;第三方final类无法修改源码,故不可通过实现Comparable改变其排序逻辑。

Comparable 是类自己定义“自然顺序”,Comparator 是外部临时定义“比较规则”——用错接口会导致 ClassCastException 或排序完全失效。
什么时候必须实现 Comparable
当你希望该类对象能直接参与 Arrays.sort()、Collections.sort(),或作为 TreeSet/TreeMap 的 key 时,就必须让类实现 Comparable 接口,并重写 compareTo() 方法。
- 一个类只能有一个
compareTo()实现,即只有一种“自然顺序” - 若类是第三方库的 final 类(如
String、Integer),你无法修改其源码,就不能靠实现Comparable来改变它的排序逻辑 -
compareTo()返回负数、0、正数,分别表示“小于”“等于”“大于”,不能只返回 -1/0/1 —— 否则链式比较(如TreeMap插入)可能出错
public class Person implements Comparable{ private String name; private int age; @Override public int compareTo(Person other) { int nameCmp = this.name.compareTo(other.name); if (nameCmp != 0) return nameCmp; return Integer.compare(this.age, other.age); // 安全比较 int,避免溢出 }}
什么时候该用 Comparator
你需要多种排序方式、无法修改原类、或只是临时一次性排序时,就该用
Comparator。它不侵入业务类,更灵活。立即学习“Java免费学习笔记(深入)”;
- 可匿名实现:
new Comparator,也可用 Lambda:() { ... } (a, b) -> a.getName().compareTo(b.getName())- JDK 8+ 提供大量静态工厂方法,比如
Comparator.comparing(Person::getName)、thenComparingInt(Person::getAge)- 注意:传给
Arrays.sort(arr, comparator)时,arr元素类型无需实现Comparable;但若元素为null,而 comparator 没处理,会抛NullPointerExceptionPerson[] people = { /* ... */ }; Arrays.sort(people, Comparator.comparing(Person::getName) .thenComparingInt(Person::getAge));Comparator 与 Comparable 同时存在时谁生效
谁被显式调用,谁就生效。两者互不影响,也不会自动“叠加”或“覆盖”。
Comparable只在没传 comparator 的默认排序中起作用。
Collections.sort(list)→ 走Comparable的compareTo()Collections.sort(list, comparator)→ 完全忽略Comparable,只用传入的comparatorTreeSet→ 依赖set = new TreeSet(); Person的ComparableTreeSet→ 完全按传入的set = new TreeSet(comparator); comparator排序,Person是否实现Comparable无关紧要容易踩的坑:null 值和比较器链断裂
最常被忽略的是
null处理和链式比较的短路行为。
- 直接调用
a.getName().compareTo(...),如果a.getName()是null,立刻NullPointerExceptionComparator.comparing(Person::getName)默认不接受null,遇到null就崩;要用comparing(Person::getName, Comparator.nullsFirst(String::compareTo))thenComparing()只有前一个比较结果为 0 时才执行,这是正确行为;但若误以为它“总会执行”,可能写出逻辑错误的多级排序- 自定义
compareTo()里用this.field - other.field算 int 差值,可能整数溢出(如Integer.MIN_VALUE - Integer.MAX_VALUE),必须用Integer.compare(a, b)










