Comparable与Comparator

  • Comparable
    public interface Comparable<T> { public int compareTo(T o); }
  • Comparator
    public interface Comparator<T> { int compare(T o1, T o2); ... }
  • 区别与联系
    举栗子:
    • Comparable Demo

      import java.util.*;
      
      public class ComparableDemo {
      
          public static void main(String[] args) {
              List<Person> people=new ArrayList<>();
              people.add(new Person(20,Person.MALE));
              people.add(new Person(22,Person.FEMALE));
              people.add(new Person(21,Person.FEMALE));
              people.add(new Person(24,Person.MALE));
      
              people.sort(null);
      //        Collections.sort(people);
              for (Person person:people) {
                  System.out.println(person);
              }
          }
      
          static class Person
              implements Comparable<Person>
          {
              int age;
              String gender;
              static final String MALE="male";
              static final String FEMALE="female";
              public Person(int age,String gender){
                  this.age=age;
                  this.gender=gender;
              }
      
              @Override
              public String toString() {
                  return "age: "+this.age+", gender: "+this.gender;
              }
      
              @Override
              public int compareTo(Person o) {
                  return this.age-o.age;
              }
          }
      }
      • 类可以通过实现Comparable接口来扩展排序功能
      • 实现了Comparable的类可以直接调用list的sort和Collections.sort来实现排序
    • Comparator Demo

      import java.util.*;
      
      public class ComparatorDemo {
      
          public static void main(String[] args) {
              List<Person> people=new ArrayList<>();
              people.add(new Person(20,Person.MALE));
              people.add(new Person(22,Person.FEMALE));
              people.add(new Person(21,Person.FEMALE));
              people.add(new Person(24,Person.MALE));
              Comparator<Person> comparator=new Comparator<Person>() {
                  @Override
                  public int compare(Person o1, Person o2) {
                      if (o1==null||o2==null)
                          return 0;
                      return o1.age-o2.age;
                  }
              };
      
              people.sort(comparator);
      //        Collections.sort(people,comparator);
      
              for (Person person:
               people) {
                  System.out.println(person);
              }
          }
      
          static class Person {
              int age;
              String gender;
              static final String MALE="male";
              static final String FEMALE="female";
              public Person(int age,String gender){
                  this.age=age;
                  this.gender=gender;
              }
      
              @Override
              public String toString() {
                  return "age: "+this.age+", gender: "+this.gender;
              }
          }
      }
      • 创建一个实现了Comparator的比较器,也可以在无法扩展bean类的时候达到排序的效果
      • Comparator和Comparable的区别就在于Comparable是由自身来实现list排序的逻辑和功能,Compartor则是通过外部来实现list排序的逻辑和功能
    • 从源代码层面来解析两者的区别:
      • Compartor:
        //先从开始调用的地方开始看: Collections.sort(people);
        转到Collections的sort源码:
        //Collections.java public static <T extends Comparable<? super T>> void sort(List<T> list) { list.sort(null); }
        这里就能看到,其实Collections也是调用了list的sort方法:
        //List.java default void sort(Comparator<? super E> c) { Object[] a = this.toArray(); Arrays.sort(a, (Comparator) c); ListIterator<E> i = this.listIterator(); for (Object e : a) { i.next(); i.set((E) e); } }
        从第二行可以看到,调用了Arrays的sort方法

        //Arrays.java
        public static <T> void sort(T[] a, Comparator<? super T> c) {
            if (c == null) {
                sort(a);
            } else {
                if (LegacyMergeSort.userRequested)
                    legacyMergeSort(a, c);
                else
                    TimSort.sort(a, 0, a.length, c, null, 0, 0);
            }
        }
        
        public static void sort(Object[] a) {
            if (LegacyMergeSort.userRequested)
                legacyMergeSort(a);
            else
                ComparableTimSort.sort(a, 0, a.length, null, 0, 0);
        }
        
            ...
        
        /** To be removed in a future release. */
        private static void legacyMergeSort(Object[] a) {
            Object[] aux = a.clone();
            mergeSort(aux, a, 0, a.length, 0);
        }
        
        private static void mergeSort(Object[] src,
                                  Object[] dest,
                                  int low,
                                  int high,
                                  int off) {
            int length = high - low;
        
            // Insertion sort on smallest arrays
            if (length < INSERTIONSORT_THRESHOLD) {
                for (int i=low; i<high; i++)
                    for (int j=i; j>low &&
                            ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)
                        swap(dest, j, j-1);
                return;
            }
        
            ....
        
            // Merge sorted halves (now in src) into dest
            for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
                if (q >= high || p < mid && ((Comparable)src[p]).compareTo(src[q])<=0)
                    dest[i] = src[p++];
                else
                    dest[i] = src[q++];
            }
        }

        从Arrays的sort方法开始,由于Compartor为null,调用只有一个参数Object[] a的sort函数,然后根据预设好的系统参数:LegacyMergeSort.userRequested来判断调用旧的归并排序函数还是调用一个更高性能的归并排序算法TimSort,这里只对legacyMergeSort进行分析,因为对于Comparable的调用过程来说基本一致,legacyMergeSort会调用mergeSort函数,在mergeSort函数中可以看到:

                ...
        
                for (int i=low; i<high; i++)
                    for (int j=i; j>low &&
                            ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)
                        swap(dest, j, j-1);
                ...
        
        会调用实现了Comparable接口的bean类的compareTo方法,因此如果没有实现Comparable接口的类调用sort(null)函数会抛出错误
      • Comparator:代码基本差不多,在Arrays的sort方法,由于Compartor不为null,根据预设好的系统参数:LegacyMergeSort.userRequested来判断调用旧的归并排序函数还是调用一个更高性能的归并排序算法TimSort,以legacyMergeSort为入口:

        private static <T> void legacyMergeSort(T[] a, int fromIndex, int toIndex,
                                            Comparator<? super T> c) {
            T[] aux = copyOfRange(a, fromIndex, toIndex);
            if (c==null)
                mergeSort(aux, a, fromIndex, toIndex, -fromIndex);
            else
                mergeSort(aux, a, fromIndex, toIndex, -fromIndex, c);
        }
        
        @SuppressWarnings({"rawtypes", "unchecked"})
        private static void mergeSort(Object[] src,
                                    Object[] dest,
                                    int low, int high, int off,
                                    Comparator c) {
            int length = high - low;
        
            // Insertion sort on smallest arrays
            if (length < INSERTIONSORT_THRESHOLD) {
                for (int i=low; i<high; i++)
                    for (int j=i; j>low && c.compare(dest[j-1], dest[j])>0; j--)
                        swap(dest, j, j-1);
                return;
            }
        
            // Recursively sort halves of dest into src
            int destLow  = low;
            int destHigh = high;
            low  += off;
            high += off;
            int mid = (low + high) >>> 1;
            mergeSort(dest, src, low, mid, -off, c);
            mergeSort(dest, src, mid, high, -off, c);
        
            // If list is already sorted, just copy from src to dest.  This is an
            // optimization that results in faster sorts for nearly ordered lists.
            if (c.compare(src[mid-1], src[mid]) <= 0) {
            System.arraycopy(src, low, dest, destLow, length);
            return;
            }
        
            // Merge sorted halves (now in src) into dest
            for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
                if (q >= high || p < mid && c.compare(src[p], src[q]) <= 0)
                    dest[i] = src[p++];
                else
                    dest[i] = src[q++];
            }
        }

        从带有Comparator参数的mergeSort函数可知:

                ...
            for (int i=low; i<high; i++)
                    for (int j=i; j>low && c.compare(dest[j-1], dest[j])>0; j--)
                        swap(dest, j, j-1);
                return;
                ...

        调用了Comparator的compare函数来比较两个bean类

posted @ 2018-11-04 23:17 戎码之路 阅读(...) 评论(...) 编辑 收藏