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)]
排序后 [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)]
排序后 [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来实现排序而不必改变对象本身;可以使用多种排序标准,比如升序、降序等。