Java 比较器 Comparable 和 Comparator

  1. Java 中对数组或者集合排序,Java提供了 `Arrays.sort()` `Collections.sort()` 两种排序方法。前者会对数组进行排序,后者会对集合进行排序。至于他们排序的规则,我们可以通过下面的两个接口来定义。
  • 对象实现 Comparable 接口,这是一个内部排序接口
  • 排序时实现 Comparator,作为参数传入到Arrays.sort()Collections.sort() ,这是一个外部排序接口

Comparable

  1. 这是一个内部排序接口,如果一个类实现了这个接口,就说明这个类是支持排序的。那么我们就可以直接通过 `Arrays.sort()` `Collections.sort()` 对该类组成的数组或者集合直接进行排序。在 `Comparable` 的官方文档中称这种排序方法为自然排序。

Comparable 接口只有一个方法 compareTo(T o) ,实现的该接口的所有类必须实现这个方法, compareTo(T o) 会返回一个 int 值,这个 int 值可能是 负数,正数和零。它的实现类会跟 compareTo(T o) 传入的对象进行比较。负数表示该对象比传入的参数小;正数表示该对象比传入的对象大;零表示该对象跟传入的对象一样大。

  1. 当然我们不一定通过数值的大小来进行排序,有可能通过其它的属性来排序,我们依然可以通过 `compareTo(T o)` 的返回值来进行排序。
  2. 如下:
  1. public class ComparableSample {
  2. static List<Person> list = new ArrayList<>();
  3. public static void main(String[] args) {
  4. list.add(new Person("Ricky", 21));
  5. list.add(new Person("Jack", 20));
  6. list.add(new Person("James", 24));
  7. list.add(new Person("Tracy", 23));
  8. list.add(new Person("Jessy", 26));
  9. list.add(new Person("Steven", 25));
  10. Collections.sort(list);
  11. list.forEach(person -> System.out.println(person.toString()));
  12. }
  13. static class Person implements Comparable<Person> {
  14. String name;
  15. int age;
  16. public Person(String name, int age) {
  17. this.name = name;
  18. this.age = age;
  19. }
  20. @Override
  21. public int compareTo(Person o) {
  22. if (this.name.length() > o.name.length()) {
  23. return 1;
  24. } else if (this.name.length() == o.name.length()) {
  25. return 0;
  26. } else {
  27. return -1;
  28. }
  29. // return this.name.length() - o.name.length()
  30. }
  31. @Override
  32. public String toString() {
  33. return "Person{" +
  34. "name='" + name + '\'' +
  35. "length='" + name.length() + "\'" +
  36. ", age=" + age +
  37. '}';
  38. }
  39. }
  40. }

如上代码,我们定义了一个 Person 类,实现了 Comparable 接口,并实现了它的 compareTo 方法。这里我们以 name的长度为标准进行排序。如果 当前的 Person 对象的name的长度大于 compareTo 传入的 Person 对象的 name的长度,就返回1,该值为正数;如果相等就返回0;如果小于就返回-1,为负数。而由于 Collections.sort(List<T> list)是对集合进行升序排列,所以运行结果如下,根据name的长度进行升序排列:

  1. Person{name='Jack'length='4', age=20}
  2. Person{name='Ricky'length='5', age=21}
  3. Person{name='James'length='5', age=24}
  4. Person{name='Tracy'length='5', age=23}
  5. Person{name='Jessy'length='5', age=26}
  6. Person{name='Steven'length='6', age=25}

上面的例子是对于当前对象与传入对象的之间比较,当我们把两者对调一下,就会变成降序排列了。

如果当前的对象去与传入对象进行比较,则为升序;如果传入对象与当前的对象比较,则为降序。

Comparator

  1. 使用 `Comparator` 接口,不需要集合或者数组的每个元素都去实现 `Comparator` ,只需在调用`Arrays.sort()` `Collections.sort()` 时传入我们自定义的对比规则。
  1. public class ComparableSample {
  2. static List<Person> list = new ArrayList<>();
  3. public static void main(String[] args) {
  4. list.add(new Person("Ricky", 21));
  5. list.add(new Person("Jack", 20));
  6. list.add(new Person("James", 24));
  7. list.add(new Person("Tracy", 23));
  8. list.add(new Person("Jessy", 26));
  9. list.add(new Person("Steven", 25));
  10. Collections.sort(list, new Comparator<Person>() {
  11. @Override
  12. public int compare(Person o1, Person o2) {
  13. return o1.name.length() - o2.name.length();
  14. }
  15. });
  16. list.forEach(person -> System.out.println(person.toString()));
  17. }
  18. static class Person {
  19. String name;
  20. int age;
  21. public Person(String name, int age) {
  22. this.name = name;
  23. this.age = age;
  24. }
  25. @Override
  26. public String toString() {
  27. return "Person{" +
  28. "name='" + name + '\'' +
  29. "length='" + name.length() + "\'" +
  30. ", age=" + age +
  31. '}';
  32. }
  33. }
  34. }

上面的代码中,Person 并没有实现任何接口,只是在调用排序方法时,传入的一个排序的规则。它的规则跟 Comparable 很像。如果集合中第一个元素与第二个比较,如果返回 0,表示两者相等;如果返回正数,表示第一个大于第二个;如果为负数表示第一个小于第二个。所以上面的代码运行结果依然是根据name 进行升序排列。

  1. Person{name='Jack'length='4', age=20}
  2. Person{name='Ricky'length='5', age=21}
  3. Person{name='James'length='5', age=24}
  4. Person{name='Tracy'length='5', age=23}
  5. Person{name='Jessy'length='5', age=26}
  6. Person{name='Steven'length='6', age=25}

总结

  1. Comparable 和 Comparator 都可以对数组或者集合进行排序
  2. Comparable 针对的是数组/集合的每一个元素的内部排序
  3. Comparator 则是在数组/集合的元素的外部定义排序规则
  4. Comparable 和 Comparator 排序规则很相似。默认都是升序排列。
  5. Comparable中如果当前对象与 compareTo(T o)传入对象对比,则为升序排列;反之为降序排列
  6. Comparator中如果compare(T o1, T o2)中的 o1 与 o2对比,则为升序排列;反之为降序排列