Comparator位于包java.util下,而Comparable位于包 java.lang下
Comparable 是一个对象本身就已经支持自比较所需要实现的接口(如 String、Integer 自己就可以完成比较大小操作,已经实现了Comparable接口)
自定义的类要在加入list容器中后能够排序,可以实现Comparable接口,在用Collections类的sort方法排序时,如果不指定Comparator,那么就以自然顺序排序,如API所说:
Sorts the specified list into ascending order, according to the natural ordering of its elements. All elements in the list must implement the Comparable interface
这里的自然顺序就是实现Comparable接口设定的排序方式。
而 Comparator 是一个专用的比较器,当这个对象不支持自比较或者自比较函数不能满足你的要求时,你可以写一个比较器来完成两个对象之间大小的比较。
可以说一个是自已完成比较,一个是外部程序实现比较的差别而已。
用 Comparator 是策略模式(strategy design pattern),就是不改变对象自身,而用一个策略对象(strategy object)来改变它的行为。
比如:你想对整数采用绝对值大小来排序,Integer 是不符合要求的,你不需要去修改 Integer 类(实际上你也不能这么做)去改变它的排序行为,只要使用一个实现了 Comparator 接口的对象来实现控制它的排序就行了。
Collections.sort((List<T> list, Comparator<? super T> c)是用来对list排序的。
如果不是调用sort方法,相要直接比较两个对象的大小,如下:
Comparator定义了俩个方法,分别是 int compare(T o1, T o2)和 boolean equals(Object obj),
用于比较两个Comparator是否相等
true only if the specified object is also a comparator and it imposes the same ordering as this comparator.
有时在实现Comparator接口时,并没有实现equals方法,可程序并没有报错,原因是实现该接口的类也是Object类的子类,而Object类已经实现了equals方法
Comparable接口只提供了 int compareTo(T o)方法,也就是说假如我定义了一个Person类,这个类实现了 Comparable接口,那么当我实例化Person类的person1后,我想比较person1和一个现有的Person对象person2的大小时,我就可以这样来调用:person1.comparTo(person2),通过返回值就可以判断了;而此时如果你定义了一个 PersonComparator(实现了Comparator接口)的话,那你就可以这样:PersonComparator comparator= new PersonComparator();
comparator.compare(person1,person2);。
两种方法各有优劣, 用Comparable 简单, 只要实现Comparable 接口的对象直接就成为一个可以比较的对象,但是需要修改源代码, 用Comparator 的好处是不需要修改源代码, 而是另外实现一个比较器, 当某个自定义的对象需要作比较的时候,把比较器和对象一起传递过去就可以比大小了, 并且在Comparator 里面用户可以自己实现复杂的可以通用的逻辑,使其可以匹配一些比较简单的对象,那样就可以节省很多重复劳动了。
Comparable Comparable 定义在 Person类的内部: public class Persion implements Comparable {..比较Person的大小..}, 因为已经实现了比较器,那么我们的Person现在是一个可以比较大小的对象了,它的比较功能和String完全一样,可以随时随地的拿来 比较大小,因为Person现在自身就是有大小之分的。Collections.sort(personList)可以得到正确的结果。 Comparator Comparator 是定义在Person的外部的, 此时我们的Person类的结构不需要有任何变化,如 public class Person{ String name; int age }, 然后我们另外定义一个比较器: public PersonComparator implements Comparator() {..比较Person的大小..}, 在PersonComparator里面实现了怎么比较两个Person的大小. 所以,用这种方法,当我们要对一个 personList进行排序的时候, 我们除了了要传递personList过去, 还需要把PersonComparator传递过去,因为怎么比较Person的大小是在PersonComparator 里面实现的, 如: Collections.sort( personList , new PersonComparator() ).
Arrays.sort(T[], Comparator < ? super T > c) 方法用于对象数组按用户自定义规则排序.
使用策略模式
这是策略模式(Strategy pattern)的一个完美又简洁的示例,值得一提的是为什么这种场景下适合使用策略模式.
总体来说,策略模式允许在程序执行时选择不同的算法.比如在排序时,传入不同的比较器(Comparator),就采用不同的算法.
根据上面的例子,假设你想要根据Dog的重量来进行排序,可以像下面这样,创建一个新的比较器来进行排序:
- class Dog{
- int size;
- int weight;
- public Dog(int s, int w){
- size = s;
- weight = w;
- }
- }
- class DogSizeComparator implements Comparator<Dog>{
- @Override
- public int compare(Dog o1, Dog o2) {
- return o1.size - o2.size;
- }
- }
- class DogWeightComparator implements Comparator<Dog>{
- @Override
- public int compare(Dog o1, Dog o2) {
- return o1.weight - o2.weight;
- }
- }
- public class ArraySort {
- public static void main(String[] args) {
- Dog d1 = new Dog(2, 50);
- Dog d2 = new Dog(1, 30);
- Dog d3 = new Dog(3, 40);
- Dog[] dogArray = {d1, d2, d3};
- printDogs(dogArray);
- Arrays.sort(dogArray, new DogSizeComparator());
- printDogs(dogArray);
- Arrays.sort(dogArray, new DogWeightComparator());
- printDogs(dogArray);
- }
- public static void printDogs(Dog[] dogs){
- for(Dog d: dogs)
- System.out.print("size="+d.size + " weight=" + d.weight + " ");
- System.out.println();
- }
- }
- size=2 weight=50 size=1 weight=30 size=3 weight=40
- size=1 weight=30 size=2 weight=50 size=3 weight=40
- size=1 weight=30 size=3 weight=40 size=2 weight=50
3. 为何使用"super"
如果使用 "Comparator < T > c" 那是很简单易懂的,但是sort的第2个参数里面的 < ? super T > 意味着比较器所接受的类型可以是T或者它的超类. 为什么是超类呢? 答案是: 这允许使用同一个比较器对不同的子类对象进行比较.在下面的示例中很明显地演示了这一点:
- import java.util.Arrays;
- import java.util.Comparator;
- class Animal{
- int size;
- }
- class Dog extends Animal{
- public Dog(int s){
- size = s;
- }
- }
- class Cat extends Animal{
- public Cat(int s){
- size = s;
- }
- }
- class AnimalSizeComparator implements Comparator<Animal>{
- @Override
- public int compare(Animal o1, Animal o2) {
- return o1.size - o2.size;
- }
- //in this way, all sub classes of Animal can use this comparator.
- }
- public class ArraySort {
- public static void main(String[] args) {
- Dog d1 = new Dog(2);
- Dog d2 = new Dog(1);
- Dog d3 = new Dog(3);
- Dog[] dogArray = {d1, d2, d3};
- printDogs(dogArray);
- Arrays.sort(dogArray, new AnimalSizeComparator());
- printDogs(dogArray);
- System.out.println();
- //when you have an array of Cat, same Comparator can be used.
- Cat c1 = new Cat(2);
- Cat c2 = new Cat(1);
- Cat c3 = new Cat(3);
- Cat[] catArray = {c1, c2, c3};
- printDogs(catArray);
- Arrays.sort(catArray, new AnimalSizeComparator());
- printDogs(catArray);
- }
- public static void printDogs(Animal[] animals){
- for(Animal a: animals)
- System.out.print("size="+a.size + " ");
- System.out.println();
- }
- }
- size=2 size=1 size=3
- size=1 size=2 size=3
- size=2 size=1 size=3
- size=1 size=2 size=3
4. 小结
与Arrays.sort()相关的信息总结如下:
- 通用: super 类
- 策略设计模式(strategy pattern);
- 归并排序(merge sort): 时间复杂度 n*log(n);
- Java.util.Collections#sort(List < T > list, Comparator < ? super T > c)与Arrays.sort 使用类似的思想.