Java 比较与排序 Comparator和Comparable与sort

Java 中有两个参与比较的接口Comparator和Comparable,它们名字相近,适用场景不同。

Comparable

Comparable 位于 JDK 的 java.lang 包中,它是 Java 集合框架中的一员。

Comparable接口定义

public interface Comparable<T> {
    public int compareTo(T o);
}

此接口只有一个方法 compareTo(),比较此对象与指定对象的顺序,如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。

Comparable 示例

定义了一个人类 Person,我们一般用的人的年龄 age 来比较大小。实现 Comparable 接口以后,重写了 compareTo() 方法。

public class Person implements Comparable<Person>{

    private String name;

    private Integer age;

    // setters、getters

    @Override
    public int compareTo(Person p) {
        return this.age - p.getAge();
    }
}

对象之间的比较,一般是为了排序,下面构造一个简单的列表,并对其排序。

private static void comparePerson(){
    Person person1 = new Person();
    person1.setAge(22);
    person1.setName("Tom");

    Person person2 = new Person();
    person2.setAge(33);
    person2.setName("Jerry");

    Person person3 = new Person();
    person3.setAge(6);
    person3.setName("Baby");

    List<Person> people = new ArrayList<>();
    people.add(person1);
    people.add(person2);
    people.add(person3);

    System.out.println("排序前    " + people);
    Collections.sort(people);
    System.out.println("排序后    " + people);
    Collections.reverse(people);
    System.out.println("反向排序后 " + people);
}
排序前 [Person(name=Tom, age=22), Person(name=Jerry, age=33), Person(name=Baby, age=6)]
排序后 [Person(name=Baby, age=6), Person(name=Tom, age=22), Person(name=Jerry, age=33)]
反向排序后 [Person(name=Jerry, age=33), Person(name=Tom, age=22), Person(name=Baby, age=6)]

Comparator

Comparator 接口位于 java.util 包中,它也是 Java 集合框架中的一员。

Comparator 接口定义

@FunctionalInterface
public interface Comparator<T> {

    int compare(T o1, T o2);
}

该接口多个方法,许多方法在 JAVA8 加入,并且已经实现了(default 默认实现)。compare(T o1, T o2) 是比较o1和o2的大小。o1比o2小,返回负数;意味着o1等于o2,返回零;o1大于o2,返回正数。

Comparator 示例

创建一个动物类 Animal,与常见的 Java 对象没有区别。

public class Animal {

    private String name;

    /**
     * 体重
     */
    private Integer weight;

    // setters、getters
}

动物之间可以通过体重来比较大小,因此,我们通过一个比较器来实现动物间的大小比较。

public class AnimalComparator implements Comparator<Animal> {
    @Override
    public int compare(Animal o1, Animal o2) {
        return o1.getWeight() - o2.getWeight();
    }
}
private static void compareAnimal(){
    Animal dog = new Animal();
    dog.setName("狗");
    dog.setWeight(10);

    Animal chicken = new Animal();
    chicken.setName("鸡");
    chicken.setWeight(2);

    Animal pig = new Animal();
    pig.setName("猪");
    pig.setWeight(60);

    List<Animal> animals = new ArrayList<>();
    animals.add(dog);
    animals.add(chicken);
    animals.add(pig);

    System.out.println("排序前    " + animals);
    animals.sort(new AnimalComparator());
    System.out.println("排序后    " + animals);
    Collections.reverse(animals);
    System.out.println("反向排序后 " + animals);
}
排序前 [Animal(name=狗, weight=10), Animal(name=鸡, weight=2), Animal(name=猪, weight=60)]
排序后 [Animal(name=鸡, weight=2), Animal(name=狗, weight=10), Animal(name=猪, weight=60)]
反向排序后 [Animal(name=猪, weight=60), Animal(name=狗, weight=10), Animal(name=鸡, weight=2)]

Comparator和Comparable 区别

  • Comparable相当于内部比较器,而Comparator相当于外部比较器。Comparable是在集合内部定义的方法实现的排序,Comparator是在集合外部实现的排序。
  • Comparable是排序接口,若一个类实现了Comparable接口,就意味着该类支持排序,可以使用Collections.sort或Arrays.sort进行自动排序。而Comparator是比较器,若需要控制某个类的次序,可以建立一个该类的比较器来进行排序。
  • 两种方法各有优劣, 用 Comparable 简单, 只要实现Comparable接口的对象直接就成为一个可以比较的对象,但是需要修改源代码。 用Comparator 的好处是不需要修改源代码, 而是另外实现一个比较器, 当某个自定义的对象需要作比较的时候,把比较器和对象一起传递过去就可以比大小了, 并且在 Comparator 里面用户可以自己实现复杂的可以通用的逻辑,使其可以匹配一些比较简单的对象,那样就可以节省很多重复劳动了。
  • Comparator 可以看成一种算法的实现,将算法和数据分离,Comparator也可以在下面两种环境下使用:类的设计师没有考虑到比较问题而没有实现 Comparable,可以通过Comparator来实现排序而不必改变对象本身;可以使用多种排序标准,比如升序、降序等。
标签: